#! /usr/bin/perl # Constructs the CXSparse package from CSparse, adding four different sets of # functions (int/UF_long, and double/complex). Backward compatible with # CSparse. No MATLAB interface is provided for CXSparse, however. # # To create CXSparse from CSparse, the ./CXSparse directory should not (yet) # exist. Use the following commands, where CSparse is the CSparse directory: # # ./CSparse_to_CXSparse CSparse CXSparse CXSparse_newfiles.tar.gz # cd CXSparse/Demo # make > cs_demo.out # # Alternatively, use "make cx", using the UFsparse/Makefile, while in the # UFsparse directory. # # Created by David Bateman, Feb. 2006, David dot Bateman atsign motorola # dot com. Modified by Tim Davis, Aug 23, 2006. use strict; use Cwd; use File::Find; use File::Basename; use Text::Wrap; use FileHandle; use IPC::Open3; my $in_dir = @ARGV[0]; my $out_dir = @ARGV[1]; my $tar_file = @ARGV[2]; #------------------------------------------------------------------------------- # copy all files from CSparse to CXSparse #------------------------------------------------------------------------------- system ("cp -pr $in_dir $out_dir") ; #------------------------------------------------------------------------------- # Add the new files from the tar file given by the third argument #------------------------------------------------------------------------------- my $old_pwd = cwd(); chdir($out_dir); system ("tar xpBvzf $old_pwd/$tar_file"); chdir($old_pwd); #------------------------------------------------------------------------------- # Convert Demo/* files #------------------------------------------------------------------------------- # convert demo *.[ch] files into the four different versions (di, dl, ci, cl) my @demo_files = ('demo1.c', 'demo2.c', 'demo3.c', 'demo.c', 'demo.h') ; foreach my $fff ( @demo_files ) { my $infile = sprintf ("%s/Demo/cs_%s", $out_dir, $fff) ; # create di version my $outfile = sprintf ("%s/Demo/cs_di_%s", $out_dir, $fff) ; if (open (OUT, ">$outfile")) { if (open (IN, $infile)) { while () { # change all "cs*" names to "cs_di*", except #include "cs.h" s/\bcs/cs_di/g ; s/cs_di\.h/cs.h/ ; print OUT $_; } close (IN); } close (OUT); } # create dl version my $outfile = sprintf ("%s/Demo/cs_dl_%s", $out_dir, $fff) ; if (open (OUT, ">$outfile")) { if (open (IN, $infile)) { while () { # change all "cs*" names to "cs_dl*", except #include "cs.h" s/\bcs/cs_dl/g ; s/cs_dl\.h/cs.h/ ; # change int to UF_long, except for "int main" s/\bint\b/UF_long/g; s/UF_long main/int main/; # change %d to %ld in printf and scanf s/\%d/\%ld/g; print OUT $_; } close (IN); } close (OUT); } # create ci version my $outfile = sprintf ("%s/Demo/cs_ci_%s", $out_dir, $fff) ; if (open (OUT, ">$outfile")) { if (open (IN, $infile)) { while () { # change all "cs*" names to "cs_ci*", except #include "cs.h" s/\bcs/cs_ci/g ; s/cs_ci\.h/cs.h/ ; # fabs becomes cabs s/fabs/cabs/g; # change double to cs_complex_t s/\bdouble\b/cs_complex_t/g; # (double) typecasts stay double s/\(cs_complex_t\) /(double) /g; # tic, toc, tol, and norm are double, not cs_complex_t s/cs_complex_t norm/double norm/; s/cs_complex_t tic/double tic/; s/cs_complex_t toc \(cs_complex_t/double toc (double/; s/cs_complex_t s = tic/double s = tic/; s/cs_complex_t tol/double tol/; # cumsum, S->lnz, S->unz are double s/cs_complex_t lnz/double lnz/; s/cs_complex_t unz/double unz/; s/cs_complex_t cs_cumsum/double cs_cumsum/; # local variable declarations that stay double s/, / ;\n double / ; print OUT $_; } close (IN); } close (OUT); } # create cl version my $outfile = sprintf ("%s/Demo/cs_cl_%s", $out_dir, $fff) ; if (open (OUT, ">$outfile")) { if (open (IN, $infile)) { while () { # change all "cs*" names to "cs_cl*", except #include "cs.h" s/\bcs/cs_cl/g ; s/cs_cl\.h/cs.h/ ; # change int to UF_long, except for "int main" s/\bint\b/UF_long/g; s/UF_long main/int main/; # change %d to %ld in printf and scanf s/\%d/\%ld/g; # fabs becomes cabs s/fabs/cabs/g; # change double to cs_complex_t s/\bdouble\b/cs_complex_t/g; # (double) typecasts stay double s/\(cs_complex_t\) /(double) /g; # tic, toc, tol, and norm are double, not cs_complex_t s/cs_complex_t norm/double norm/; s/cs_complex_t tic/double tic/; s/cs_complex_t toc \(cs_complex_t/double toc (double/; s/cs_complex_t s = tic/double s = tic/; s/cs_complex_t tol/double tol/; # cumsum, S->lnz, S->unz are double s/cs_complex_t lnz/double lnz/; s/cs_complex_t unz/double unz/; s/cs_complex_t cs_cumsum/double cs_cumsum/; # local variable declarations that stay double s/, / ;\n double / ; print OUT $_; } close (IN); } close (OUT); } } #------------------------------------------------------------------------------- # Convert Source/*.c files (except cs_house.c) #------------------------------------------------------------------------------- # note that cs.h, cs_house.c, cs_updown.c, ... # are not included in this list my @src_files = ('Source/cs_add.c', 'Source/cs_amd.c', 'Source/cs_chol.c', 'Source/cs_cholsol.c', 'Source/cs_counts.c', 'Source/cs_cumsum.c', 'Source/cs_dfs.c', 'Source/cs_dmperm.c', 'Source/cs_droptol.c', 'Source/cs_dropzeros.c', 'Source/cs_dupl.c', 'Source/cs_entry.c', 'Source/cs_etree.c', 'Source/cs_fkeep.c', 'Source/cs_gaxpy.c', 'Source/cs_happly.c', 'Source/cs_ipvec.c', 'Source/cs_load.c', 'Source/cs_lsolve.c', 'Source/cs_ltsolve.c', 'Source/cs_lu.c', 'Source/cs_lusol.c', 'Source/cs_malloc.c', 'Source/cs_maxtrans.c', 'Source/cs_multiply.c', 'Source/cs_norm.c', 'Source/cs_permute.c', 'Source/cs_pinv.c', 'Source/cs_post.c', 'Source/cs_print.c', 'Source/cs_pvec.c', 'Source/cs_qr.c', 'Source/cs_qrsol.c', 'Source/cs_scatter.c', 'Source/cs_scc.c', 'Source/cs_schol.c', 'Source/cs_sqr.c', 'Source/cs_symperm.c', 'Source/cs_tdfs.c', 'Source/cs_transpose.c', 'Source/cs_compress.c', 'Source/cs_usolve.c', 'Source/cs_util.c', 'Source/cs_utsolve.c', 'Source/cs_reach.c', 'Source/cs_spsolve.c', 'Source/cs_leaf.c', 'Source/cs_ereach.c', 'Source/cs_randperm.c' ) ; foreach my $file ( @src_files ) { my $infile = sprintf ("%s/%s", $in_dir, $file) ; my $outfile = sprintf ("%s/%s", $out_dir, $file) ; my $fbase = basename($file,('.c')); if (open(OUT,">$outfile")) { if (open(IN,$infile)) { # my $qrsol_beta_seen = 0; while () { # change the name of the package (for cs_print.c) s/CSparse/CXSparse/g; # fabs becomes CS_ABS s/fabs/CS_ABS/g; # change int to CS_INT s/\bint\b/CS_INT/g; # change %d to "CS_ID" in printf and scanf (except version #'s) s/\%d/"CS_ID"/g; s/"CS_ID"\."CS_ID"\."CS_ID"/%d.%d.%d/; # change double to CS_ENTRY s/\bdouble\b/CS_ENTRY/g; # (double) and (double *) typecasts stay double, # tol and vnz for cs_vcount stays double s/\(CS_ENTRY\) /(double) /g; s/\(CS_ENTRY \*\) /(double \*) /; s/CS_ENTRY tol/double tol/; s/CS_ENTRY \*vnz/double \*vnz/; # local variable declarations that stay double s/, / ;\n double / ; # nargin and nargout stay "int" for MATLAB mexFunctions s/CS_INT nargin/int nargin/; s/CS_INT nargout/int nargout/; #--------------------------------------------------------------- # Special cases. Some undo changes made above. #--------------------------------------------------------------- # cs_mex.c if ($fbase =~ /cs_mex/) { s/matrix must be CS_ENTRY/matrix must be double/; s/A->p =/A->p = (CS_INT *)/; s/A->i =/A->i = (CS_INT *)/; s/, A->p/, (mwIndex *) A->p/; s/, A->i/, (mwIndex *) A->i/; } # fix comments in cs_add_mex.c and cs_permute_mex.c if ($fbase =~ /cs_add_mex/ || $fbase =~ /cs_permute_mex/) { s/via CS_ENTRY transpose/via double transpose/; } # cs_chol if ($fbase =~ /cs_chol/) { s/\(d <= 0\)/(CS_REAL (d) <= 0 || CS_IMAG (d) != 0)\n\t /; s/lki \* lki/lki * CS_CONJ (lki)/; s/ = lki/ = CS_CONJ (lki)/; } # cs_norm if ($fbase =~ /cs_norm/) { s/^CS_ENTRY cs_norm/double cs_norm/; } # cs_cumsum if ($fbase =~ /cs_cumsum/) { s/CS_ENTRY/double/; } # cs_transpose if ($fbase =~ /cs_transpose/) { s/Ax \[p\]/(values > 0) ? CS_CONJ (Ax [p]) : Ax [p]/; } # cs_symperm if ($fbase =~ /cs_symperm/) { s/Ax \[p\]/(i2 <= j2) ? Ax [p] : CS_CONJ (Ax [p])/; } # cs_qr if ($fbase =~ /cs_qr/) { s/n, sizeof \(CS_ENTRY\)/n, sizeof (double)/; } # cs_happly if ($fbase =~ /cs_happly/) { s/^(.*tau.*)(Vx\s*\[p\])/$1CS_CONJ ($2)/; s/CS_ENTRY beta/double beta/; } # cs_ltsolve if ($fbase =~ /cs_ltsolve/) { s/(Lx \[.*?\])(\s+[\*;])/CS_CONJ ($1)$2/; } # cs_utsolve if ($fbase =~ /cs_utsolve/) { s/(Ux \[.*?\])(\s+[\*;])/CS_CONJ ($1)$2/; } # cs_load if ($fbase =~ /cs_load/) { s/CS_ENTRY x ;/double x ;\n#ifdef CS_COMPLEX\n double xi ;\n#endif/ ; s/^(\s*while.*)%lg(.*)&x\) == 3(.*)$/#ifdef CS_COMPLEX\n$1%lg %lg$2&x, &xi) == 4$3\n#else\n$1%lg$2&x) == 3$3\n#endif/; s/(.*cs_entry.*), x(.*)$/#ifdef CS_COMPLEX\n$1, x + xi*I$2\n#else\n$1, x$2\n#endif/ } # cs_print if ($fbase =~ /cs_print/) { s/^(.*)%g(.*)Ax\s*\?\s*Ax\s*\[p\]\s*:\s*1(.*)/#ifdef CS_COMPLEX\n$1(%g, %g)$2\n\t\t Ax ? CS_REAL (Ax [p]) : 1, Ax ? CS_IMAG (Ax [p]) : 0$3\n#else\n$1%g$2Ax ? Ax [p] : 1$3\n#endif/; } print OUT $_; } close (IN); } close (OUT); } }