[Pntool-developers] SF.net SVN: pntool:[230] spnbox
Brought to you by:
compaqdrew,
miordache
From: <Ste...@us...> - 2009-08-21 19:18:27
|
Revision: 230 http://pntool.svn.sourceforge.net/pntool/?rev=230&view=rev Author: StephenCamp Date: 2009-08-21 19:18:18 +0000 (Fri, 21 Aug 2009) Log Message: ----------- Added optimized row/column swap operations in extendedmatrix.c and appropriate test routines. Modified mroadm.c and reduce.c to use the new optimized row/column swaps. Modified Paths: -------------- spnbox/README.txt spnbox/extendedmatrix.c spnbox/extendedmatrix.h spnbox/mroadm.c spnbox/reduce.c spnbox/tests/Makefile spnbox/tests/test-extendedmatrix.c spnbox/tests/test-extendedmatrix.txt Modified: spnbox/README.txt =================================================================== --- spnbox/README.txt 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/README.txt 2009-08-21 19:18:18 UTC (rev 230) @@ -1,45 +1,94 @@ #ABOUT -SPNBOX implements the Petri net supervisory control functions originally developed by Dr. Iordache for Matlab. +SPNBOX implements the Petri net supervisory control functions originally developed +for Matlab by Dr. Marian V. Iordache. +The functions were converted to C for use with the ACTS tool by Stephen Camp. + #COMPILING -To generate object files for the entire SPNBOX toolset, run "make" from the pntool/spnbox directory. +To generate object files for the entire SPNBOX toolset, run "make" from the +pntool/spnbox directory. -Note that SPNBOX makes use of the LPSOLVE MILP solver API found in the pntool/third-party directory. The makefile will attempt to copy the compiled library liblpsolve55.a from the LPSOLVE directories into the pntool/spnbox directory if it is not already present. If the LPSOLVE library is not present in its own directory, the SPNBOX makefile will invoke LPSOLVE's linux-targeted makefile to build the lpsolve library. +Note that SPNBOX makes use of the LPSOLVE MILP solver API found in the +pntool/third-party directory. The makefile will attempt to copy the compiled +library liblpsolve55.a from the LPSOLVE directories into the pntool/spnbox +directory if it is not already present. If the LPSOLVE library is not present in +its own directory, the SPNBOX makefile will invoke LPSOLVE's linux-targeted +makefile to build the lpsolve library. #TESTING -The subdirectory "tests" contains test files for the SPNBOX functions. There are source files for a test program for each function except chkcons, which is used as a subroutine of other functions and so tested implicitly. -The makefile within the directory will make any of the test programs. To generate the test program for a particular function, use a command of the form: +The subdirectory "tests" contains test files for the SPNBOX functions. There are +source files for a test program for each function except chkcons, which is used +as a subroutine of other functions and so tested implicitly. +The makefile within the directory will make any of the test programs. To generate +the test program for a particular function, use a command of the form: make <functionname> This will generate an executable called <functionname>.exe. -Note that the makefile can be configured to include a set of debugging routines from the third-party library memwatch that will aid in debugging memory errors. See MEMORY DEBUGGING later in this file for more information. To include this library, the "USEMEMWATCH" variable in the test makefile should be set to "yes". If it is set to anything else the memory debugging routines will not be included. +Note that the makefile can be configured to include a set of debugging routines +from the third-party library memwatch that will aid in debugging memory errors. +See MEMORY DEBUGGING later in this file for more information. To include this +library, the "USEMEMWATCH" variable in the test makefile should be set to "yes". +If it is set to anything else the memory debugging routines will not be included. + make all will generate test executables for all spnbox functions. -To test the various functions in the matrixmath.c file, use make matrixmath. To test the functions in the extendedmatrix.c file, use make extendedmatrix. -For all with such test programs except that ipslv, the test program is implemented as a program that will read from an input stream containing text in a human-readable format, interpret the text as parameters to the function, make a function call, and display the results. For format specifications, see the comments in StructuredIO.c/h. -The programs may be invoked with a single command line argument, which will be taken as the name of a text file from which to read the input. If no command line argument is used the test programs will take input from the console. +To test the various functions in the matrixmath.c file, use make matrixmath. To +test the functions in the extendedmatrix.c file, use make extendedmatrix. -Pre-formatted test scripts with problems to test each part of a function have been provided. These are named in the form test-<functionname>.txt. There is no test script for admcon.c as the admcon function is thoroughly tested by its use within the dp function. +For all with such test programs except that ipslv, the test program is implemented +as a program that will read from an input stream containing text in a human- +readable format, interpret the text as parameters to the function, make a function +call, and display the results. For format specifications, see the comments in +StructuredIO.c/h. -Thus, to test ipsolve with the default test script the following command sequence might be issued: +The programs may be invoked with a single command line argument, which will be +taken as the name of a text file from which to read the input. If no command line +argument is used the test programs will take input from the console. +Pre-formatted test scripts with problems to test each part of a function have +been provided. These are named in the form test-<functionname>.txt. There is no +test script for admcon.c as the admcon function is thoroughly tested by its use +within the dp function. + +Thus, to test ipsolve with the default test script the following command sequence +might be issued: + cd ~/pntool/spnbox/tests make ipsolve ./ipsolve test-ipsolve.txt #MEMORY DEBUGGING -The test makefile can compile and link the spnbox files so that their test routines will make use of the "memwatch" memory debugger. Memwatch is a set of routines, declared in memwatch.h in the pntool/third-party/memwatch-2.71/ directory, that overrides the standard memory allocation and deallocation functions with its own wrappers. -Memwatch keeps track of allocations and deallocations through its routines. It can detect some but not all array overwrites, underwrites, wild pointer writes, deallocations of invalid pointers, and various other potential errors related to dynamically allocated memory. -When a program that contains the Memwatch routines runs it will create a text file in the current directory, titled memwatch.log by default, that lists any errors or anomalies detected by the memwatch routines. +The test makefile can compile and link the spnbox files so that their test +routines will make use of the "memwatch" memory debugger. Memwatch is a set of +routines, declared in memwatch.h in the pntool/third-party/memwatch-2.71/ +directory, that overrides the standard memory allocation and deallocation +functions with its own wrappers. + +Memwatch keeps track of allocations and deallocations through its routines. It +can detect some but not all array overwrites, underwrites, wild pointer writes, +deallocations of invalid pointers, and various other potential errors related to +dynamically allocated memory. + +When a program that contains the Memwatch routines runs it will create a text +file in the current directory, titled memwatch.log by default, that lists any +errors or anomalies detected by the memwatch routines. + Note that the memwatch routines slow memory-related operations drastically. + See pntool/third-party/memwatch-2.71/USING for more information. -memwatch is licensed under the GNU public license, present in the file pntool/third-party/memwatch-2.71/gpl.txt. +memwatch is licensed under the GNU public license, present in the file +pntool/third-party/memwatch-2.71/gpl.txt. #FILES Main directory: - spnbox.h: This is the header file containing the definitions for all the SPNBOX functions, as well as various constant definitions. -- matrixmath.h & matrixmath.c: These implement various matrix operations used by - other SPNBOX functions. +- matrixmath.h & matrixmath.c: These implement various matrix arithmetic operations + used by other SPNBOX functions. +- extendedmatrix.h & extendedmatrix.c: These implement operations to insert or + remove rows and columns from matrices. Note that these functions employ when + possible optimizations that rely heavily on the internal details of matrix + implementation, and so if the matrix implementation is ever changed these + files will need to be modified accordingly. - deallocation.c: This implements functions to deallocate the structures returned by SPNBOX functions. - Makefile: This is the main makefile. When used without a target it builds Modified: spnbox/extendedmatrix.c =================================================================== --- spnbox/extendedmatrix.c 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/extendedmatrix.c 2009-08-21 19:18:18 UTC (rev 230) @@ -345,6 +345,66 @@ return *m; } +void SwapRows(matrix* a, matrix* b, int rowA, int rowB) +{ + if (! (a && b)) + { + merror(0, "SWAPROWS/COLUMNS: One of the matrix pointers is null"); + return; + } + if (NumberOfColumns(*a) != NumberOfColumns(*b)) + { + merror(0, "SWAPROWS/COLUMNS: The dimensions of the matrices do not agree"); + return; + } + if (rowA < 0 || rowA >= NumberOfRows(*a) || rowB < 0 || rowB >= NumberOfRows(*b)) + { + merror(0, "SWAPROWS/COLUMNS: One of the row/column numbers is out of range"); + return; + } + /*If a and b refer to the same matrix and the same row numbers are used, + no operation is necessary.*/ + if (a == b && rowA == rowB) return; + + /*If the matrices are type-2 untransposed, do a swap of the pointers in ar + rather than copying whole rows.*/ + if (a->type == 2 && b->type == 2 && !(a->trans || b->trans)) + { + mtype* temp = b->ar[rowB]; + b->ar[rowB] = a->ar[rowA]; + a->ar[rowA] = temp; + } + /*Otherwise we'll have to iterate through the whole row and do a copy-type + swap.*/ + else + { + int temp, i; + for (i = 0; i < NumberOfColumns(*a); i++) + { + temp = GetMatrixEl(a, rowA, i); + SetMatrixEl(a, rowA, i, GetMatrixEl(b, rowB, i)); + SetMatrixEl(b, rowB, i, temp); + } + } +} + +void SwapColumns(matrix *a, matrix* b, int colA, int colB) +{ + if (a && b) + { + TransposeMatrix(a); + TransposeMatrix(b); + SwapRows(a, b, colA, colB); + TransposeMatrix(a); + TransposeMatrix(b); + } + else + { + merror(0, "SWAPROWS/COLUMNS: One of the matrix pointers is null"); + return; + } +} + void OptimizeRows(matrix* m) { matrix newM; Modified: spnbox/extendedmatrix.h =================================================================== --- spnbox/extendedmatrix.h 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/extendedmatrix.h 2009-08-21 19:18:18 UTC (rev 230) @@ -84,6 +84,20 @@ (reducing computational complexity by a factor at least equal to the number of rows in the matrix) if and only if the matrix is a type-2 transposed.*/ +void SwapRows(matrix* a, matrix* b, int rowA, int rowB); +/*SwapRows exchanges the contents of the rowA'th row of A with the rowB'th row of +B. If both matrices are type-2 untransposed, the function employs an optimization +that reduces computational complexity by a factor equal to the number of columns +in the matrices. +a and b can point to the same matrix.*/ + +void SwapColumns(matrix *a, matrix* b, int colA, int colB); +/*SwapColumns exchanges the contents of the colA'th column of A with the colB'th +column of B. If both matrices are type-2 transposed, the function employs an +optimization that reduces computational complexity by a factor equal to the +number of rows in the matrices. +a and b can point to the same matrix.*/ + void OptimizeRows(matrix *m); /*OptimizeRows modifies the matrix passed to it so that its use with the row- manipulation functions will be optimized for speed.*/ Modified: spnbox/mroadm.c =================================================================== --- spnbox/mroadm.c 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/mroadm.c 2009-08-21 19:18:18 UTC (rev 230) @@ -2,6 +2,7 @@ #include "../pnheaders/general.h" #include "../pnheaders/matrix.h" #include "matrixmath.h" +#include "extendedmatrix.h" #include "spnbox.h" typedef struct mroadm_d @@ -297,10 +298,6 @@ { int success = 1, i, j, upperlimit; upperlimit = d->places; - /*At some point we are going to need to swap some rows of M. Allocate a - matrix to hold intermediate values.*/ - matrix mrow; - AllocateMatrixType(1, &mrow, 1, NumberOfColumns(d->M)); for (i = 0; i < upperlimit; i++) { /*See if there are any elements below the main diagonal less than 0.*/ @@ -312,10 +309,7 @@ { if (j != i) { - /*Swap rows*/ - CopyBlock(1, NumberOfColumns(d->M), &d->M, i, 0, &mrow, 0, 0); - CopyBlock(1, NumberOfColumns(d->M), &d->M, j, 0, &d->M, i, 0); - CopyBlock(1, NumberOfColumns(d->M), &mrow, 0, 0, &d->M, j, 0); + SwapRows(&d->M, &d->M, i, j); } czero(d, i, i); } @@ -352,7 +346,6 @@ } if (i < d->places + d->conversionCount) success = 0; } - DeallocateMatrix(&mrow); return success; } @@ -362,10 +355,6 @@ { int success = 1, i, j, k, upperlimit; upperlimit = d->places; - /*At some point we are going to need to swap some rows of M. Allocate a - matrix to hold intermediate values.*/ - matrix mrow; - AllocateMatrixType(1, &mrow, 1, NumberOfColumns(d->M)); for (i = 0; i < upperlimit; i++) { /*See if there are any elements below the main diagonal less than 0.*/ @@ -375,10 +364,7 @@ } if (k < d->places && k != i) { - /*Swap rows*/ - CopyBlock(1, NumberOfColumns(d->M), &d->M, i, 0, &mrow, 0, 0); - CopyBlock(1, NumberOfColumns(d->M), &d->M, k, 0, &d->M, i, 0); - CopyBlock(1, NumberOfColumns(d->M), &mrow, 0, 0, &d->M, k, 0); + SwapRows(&d->M, &d->M, i, k); } if (k < d->places) { @@ -397,10 +383,7 @@ { if (j != i) { - /*Swap rows*/ - CopyBlock(1, NumberOfColumns(d->M), &d->M, i + k, 0, &mrow, 0, 0); - CopyBlock(1, NumberOfColumns(d->M), &d->M, j, 0, &d->M, i + k, 0); - CopyBlock(1, NumberOfColumns(d->M), &mrow, 0, 0, &d->M, j, 0); + SwapRows(&d->M, &d->M, i + k, j); } czero(d, i + k, i); } @@ -424,7 +407,6 @@ break; } } - DeallocateMatrix(&mrow); } /******************************************************************************* Modified: spnbox/reduce.c =================================================================== --- spnbox/reduce.c 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/reduce.c 2009-08-21 19:18:18 UTC (rev 230) @@ -2,6 +2,7 @@ #include "../pnheaders/matrix.h" #include "../pnheaders/pns.h" #include "spnbox.h" +#include "extendedmatrix.h" static void ExtractConstraint(matrix* L, matrix* l, int* B, int* b, int Constraint); static void RestoreConstraint(matrix* L, matrix* l, int* B, int b, int Constraint); @@ -99,17 +100,14 @@ return result; } /******************************************************************************* -ExtractConstraint takes the given constraint row from L and B, copies it to the -single-row parameters l and b, and zeros it in L in preparation for redundancy -tests with chkcons.*/ +ExtractConstraint nulls out l and swaps its single row with the given constraint +row from L. It swaps out the proper element of B and b as well. This is in +preparation for redundancy tests with chkcons.*/ void ExtractConstraint(matrix* L, matrix* l, int* B, int* b, int Constraint) { int i; - for (i = 0; i < NumberOfColumns(*L); i++) - { - SetMatrixEl(l, 0, i, GetMatrixEl(L, Constraint, i)); - SetMatrixEl(L, Constraint, i, 0); - } + MakeZeroRow(l, 0); + SwapRows(L, l, Constraint, 0); *b = B[Constraint]; B[Constraint] = 0; } @@ -120,9 +118,6 @@ void RestoreConstraint(matrix* L, matrix* l, int* B, int b, int Constraint) { int i; - for (i = 0; i < NumberOfColumns(*L); i++) - { - SetMatrixEl(L, Constraint, i, GetMatrixEl(l, 0, i)); - } + SwapRows(L, l, Constraint, 0); B[Constraint] = b; } Modified: spnbox/tests/Makefile =================================================================== --- spnbox/tests/Makefile 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/tests/Makefile 2009-08-21 19:18:18 UTC (rev 230) @@ -6,7 +6,7 @@ #This variable controls whether or not the memwatch memory debugging routines are included in #compilation. Set to "yes" to include them and "no" to leave them out. -USEMEMWATCH = yes +USEMEMWATCH = no #Assign the default compiler call and options. COMPILER=gcc -g @@ -43,11 +43,11 @@ ADMCON=admcon.o $(EXTENDEDMATRIX) $(IPSOLVE) ASIPH=asiph.o $(ACTN) $(EXTENDEDMATRIX) ILPADM=ilpadm.o $(IPSOLVE) -MROADM=mroadm.o $(GCDV) +MROADM=mroadm.o $(EXTENDEDMATRIX) $(GCDV) LINENF=linenf.o $(ILPADM) $(MROADM) NLTRANS=nltrans.o $(IPSOLVE) PN2EACPN=pn2eacpn.o $(NLTRANS) -REDUCE=reduce.o chkcons.o $(IPSOLVE) +REDUCE=reduce.o chkcons.o $(EXTENDEDMATRIX) $(IPSOLVE) TACTN=tactn.o $(IPSOLVE) DP=dp.o tactn.o reduce.o chkcons.o pn2eacpn.o nltrans.o asiph.o actn.o admcon.o supervis.o msplit.o issiph.o fvpr.o avpr.o $(EXTENDEDMATRIX) $(IPSOLVE) DP4=dp4.o tactn.o reduce.o chkcons.o pn2acpn.o nltrans.o asiph.o actn.o admcon.o supervis.o msplit.o issiph.o fvpr.o avpr.o $(EXTENDEDMATRIX) $(IPSOLVE) Modified: spnbox/tests/test-extendedmatrix.c =================================================================== --- spnbox/tests/test-extendedmatrix.c 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/tests/test-extendedmatrix.c 2009-08-21 19:18:18 UTC (rev 230) @@ -27,6 +27,10 @@ static void SInsertNullC(int Size, int Reps, int Col, int Cols, int Optimized); static void TInsertNullR(matrix *A, int Row, int Rows, int Mode, int Optimized); static void TInsertNullC(matrix *A, int Col, int Cols, int Mode, int Optimized); +static void TSwapR(matrix* A, matrix* B, int Row, int Optimized); +static void TSwapC(matrix* A, matrix* B, int Col, int Optimized); +static void SSwapR(int Size, int Reps, int Row, int Optimized); +static void SSwapC(int Size, int Reps, int Col, int Optimized); static void TOptimizeR(matrix *A); static void TOptimizeC(matrix *A); @@ -127,6 +131,28 @@ TRemoveC(&A, Column, Columns, Mode, Optimized); } } + else if (! strcmp(Operation, "SwapRows")) + { + if (SpeedTest) + { + SSwapR(Size, Reps, Row, Optimized); + } + else + { + TSwapR(&A, &B, Row, Optimized); + } + } + else if (! strcmp(Operation, "SwapColumns")) + { + if (SpeedTest) + { + SSwapC(Size, Reps, Column, Optimized); + } + else + { + TSwapC(&A, &B, Column, Optimized); + } + } else if (! strcmp(Operation, "OptimizeRows")) { TOptimizeR(&A); @@ -438,12 +464,96 @@ if (Mode >= 0) DeallocateMatrix(&result); } +void TSwapR(matrix* A, matrix* B, int Row, int Optimized) +{ + printf("Testing row swap: A(%d,:) <-> B(%d,:).\n", Row, 0); + printf("Optimization: %s.\n", Optimized ? "Yes" : "No"); + ShowMatrix(A, "A Before"); + ShowMatrix(B, "B Before"); + if (Optimized) + { + OptimizeRows(A); + OptimizeRows(B); + } + else + { + OptimizeColumns(A); + OptimizeColumns(B); + } + SwapRows(A, B, Row, 0); + ShowMatrix(A, "A After"); + ShowMatrix(B, "B After"); +} + +void TSwapC(matrix* A, matrix* B, int Col, int Optimized) +{ + printf("Testing column swap: A(:,%d) <-> B(:,%d).\n", Col, 0); + printf("Optimization: %s.\n", Optimized ? "Yes" : "No"); + ShowMatrix(A, "A Before"); + ShowMatrix(B, "B Before"); + if (! Optimized) + { + OptimizeRows(A); + OptimizeRows(B); + } + else + { + OptimizeColumns(A); + OptimizeColumns(B); + } + SwapColumns(A, B, Col, 0); + ShowMatrix(A, "A After"); + ShowMatrix(B, "B After"); +} + +void SSwapR(int Size, int Reps, int Row, int Optimized) +{ + printf("Speed-testing row swap (%s).\n", Optimized ? "optimized" : "unoptimized"); + + printf("Swapping the %d-th rows of two empty square matrices of size %d, %d times.\n", Row, Size, Reps); + + matrix *a = AllocateMatrices(Size, Size, Reps, ! Optimized); + matrix *b = AllocateMatrices(Size, Size, Reps, ! Optimized); + + clock_t t0 = clock(); + int i; + for (i = 0; i < Reps; i++) + { + SwapRows(a + i, b + i, Row, Row); + } + double time = ((double) (clock() - t0)) / ((double) CLOCKS_PER_SEC); + printf("Time: %.2f ms\n", time * 1000.0); + DeallocateMatrices(Reps, a); + DeallocateMatrices(Reps, b); +} + +void SSwapC(int Size, int Reps, int Col, int Optimized) +{ + printf("Speed-testing column swap (%s).\n", Optimized ? "optimized" : "unoptimized"); + + printf("Swapping the %d-th columns of two empty square matrices of size %d, %d times.\n", Col, Size, Reps); + + matrix *a = AllocateMatrices(Size, Size, Reps, Optimized); + matrix *b = AllocateMatrices(Size, Size, Reps, Optimized); + + clock_t t0 = clock(); + int i; + for (i = 0; i < Reps; i++) + { + SwapColumns(a + i, b + i, Col, Col); + } + double time = ((double) (clock() - t0)) / ((double) CLOCKS_PER_SEC); + printf("Time: %.2f ms\n", time * 1000.0); + DeallocateMatrices(Reps, a); + DeallocateMatrices(Reps, b); +} + void TOptimizeR(matrix *A) { ShowMatrix(A, "A before row optimization"); OptimizeRows(A); ShowMatrix(A, "A after row optimization"); - printf("A is %stransposed", A->trans ? "" : "un"); + printf("A is %stransposed.\n", A->trans ? "" : "un"); } void TOptimizeC(matrix *A) Modified: spnbox/tests/test-extendedmatrix.txt =================================================================== --- spnbox/tests/test-extendedmatrix.txt 2009-08-21 16:14:28 UTC (rev 229) +++ spnbox/tests/test-extendedmatrix.txt 2009-08-21 19:18:18 UTC (rev 230) @@ -138,7 +138,7 @@ columns 1 optimization yes done -quit + echo Problem 13. Null row insertion, unoptimized speedtest. operation InsertNullRows size 20 @@ -215,4 +215,49 @@ operation OptimizeColumns done +echo Problem 21. Row Swap. +A 3 3 +1 2 3 +4 5 6 +7 8 9 +B 3 3 +10 11 12 +13 14 15 +16 17 18 +row 1 +operation SwapRows +optimization no +done + +echo Problem 22. Column Swap. +A 3 3 +1 2 3 +4 5 6 +7 8 9 +B 3 3 +10 11 12 +13 14 15 +16 17 18 +column 1 +operation SwapColumns +optimization yes +done + +echo Problem 23. Speed-test row swap (unoptimized). +size 10 +repetitions 20000 +row 3 +optimization no +speedtest yes +operation SwapRows +done + +echo Problem 24. Speed-test row swap (optimized). +size 10 +repetitions 20000 +row 3 +optimization yes +speedtest yes +operation SwapRows +done quit This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |