danbaron
01-08-2010, 08:11
Here is a PowerBASIC program which times matrix inversions.
It was made with the PowerBASIC Console Compiler, version 5.
As it is, the program will not compile using the PowerBASIC Windows Compiler.
The program fills an N x N matrix with random doubles in the range of [0, 1),
and inverts it using the PowerBASIC internal function, "MAT INV()".
It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV1.TXT".
If every value of the N-dimensional check vector is very close to 1, then the inversion is correct.
The program then fills the N x N matrix again with the same set of random doubles,
and inverts it using the coded subroutine (in the program), "INV2()".
It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV2.TXT".
If every value of the N-dimensional check vector is very close to 1, then the second inversion is also correct.
The program runs in a console window, and writes its progress in the window, as it executes.
"INV2()", is coded as a subroutine, because the compiler does not permit users to code functions which return arrays.
The program could be modified to compile using the PowerBASIC Windows Compiler. But, I am not sufficiently motivated to do it.
I noticed one interesting phenomenon. Each time the program runs, two check vectors are written to files,
one for the inversion using PowerBASIC's function, "MAT INV()", and the other for the inversion using the coded subroutine, "INV2()".
For every program run, my experience is that the two check vectors are exactly identical to each other.
I ran the program three times for a 1000 x 1000 matrix.
I.F. = PowerBASIC's internal function, "MAT INV()"
C.S. = the program's coded subroutine, "INV2()"
The times were (seconds),
I.F. ***C.S.
105.881 54.896
104.301 54.863
104.918 55.051
I attached the program file below. I called it, "MATINV.TXT".
(The forum will not permit me to attach a file with the extension, "BAS".)
If you download it, then rename it to, "MATINV.BAS", before you compile it.
(If, by chance, an inversion starts before midnight, and finishes after midnight, the elapsed time for it will be wrong (crazily wrong).)
:oops: :x :twisted:
Dan
'************************************************************************************************************
' FILE = "MATINV.BAS"
' Made with the PowerBASIC Console Compiler, version 5.
' As it is, the program will not compile using the PowerBASIC Windows Compiler.
' The program fills an N x N matrix with random doubles in the range of [0, 1),
' and inverts it using the PowerBASIC internal function, "MAT INV()".
' It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV1.TXT".
' If every value of the N-dimensional check vector is very close to 1, then the inversion is correct.
' The program then fills the N x N matrix again with the same set of random doubles,
' and inverts it using the coded subroutine shown below, "INV2()".
' It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV2.TXT".
' If every value of the N-dimensional check vector is very close to 1, then the second inversion is also correct.
' "INV2()", is coded as a subroutine, because the compiler does not permit users to code functions which return arrays.
' The program could be modified to compile using the PowerBASIC Windows Compiler. But, I am not sufficiently motivated to do it.
' I noticed one interesting phenomenon. Each time the program runs, two check vectors are written to files,
' one for the inversion using PowerBASIC's function, "MAT INV()", and the other for the inversion using the coded subroutine, "INV2()".
' For every program run, my experience is that the two check vectors are exactly identical to each other.
'************************************************************************************************************
#COMPILE EXE
#DIM ALL
'Set the size of the N x N matrix to invert, on the next line.
%N = 1000
$FN1 = "MATINV1.TXT"
$FN2 = "MATINV2.TXT"
GLOBAL DATE AS STRING
GLOBAL TIME AS STRING
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
FUNCTION PBMAIN() AS LONG
DIM T0 AS DOUBLE
DIM T1 AS DOUBLE
DIM T2 AS DOUBLE
DIM TT AS DOUBLE
DIM A0(1 TO %N, 1 TO %N) AS DOUBLE
DIM AI(1 TO %N, 1 TO %N) AS DOUBLE
DIM ID(1 TO %N, 1 TO %N) AS DOUBLE
DIM VA(1 TO %N) AS DOUBLE
DIM VB(1 TO %N) AS DOUBLE
'---------------------------------------------
DATE = DATE$
TIME = TIME$
T0 = TIMER
'---------------------------------------------
CALL CONSOLEOUTPUT(1, TT)
RANDOMIZE T0
CALL INITIALIZEARRAYS(A0(), AI(), VA())
T1 = TIMER
MAT AI() = INV(A0())
T2 = TIMER
TT = T2 - T1
CALL CONSOLEOUTPUT(2, TT)
MAT ID = A0 * AI
MAT VB = ID * VA
CALL WRITEFILE(1, VB(), TT)
CALL CONSOLEOUTPUT(3, TT)
'---------------------------------------------
RANDOMIZE T0
CALL INITIALIZEARRAYS(A0(), AI(), VA())
T1 = TIMER
CALL INV2(AI())
T2 = TIMER
TT = T2 - T1
CALL CONSOLEOUTPUT(4, TT)
MAT ID = A0 * AI
MAT VB = ID * VA
CALL WRITEFILE(2, VB(), TT)
'---------------------------------------------
CALL CONSOLEOUTPUT(5, TT)
WAITKEY$
END FUNCTION
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB INITIALIZEARRAYS(A1() AS DOUBLE, A2() AS DOUBLE, V() AS DOUBLE)
LOCAL FIRST AS LONG
LOCAL LAST AS LONG
LOCAL N AS LONG
LOCAL I AS WORD
LOCAL J AS WORD
LOCAL D AS DOUBLE
FIRST = LBOUND(A1(1))
LAST = UBOUND(A2(1))
N = LAST - FIRST + 1
FOR I = FIRST TO LAST
V(I) = 1
FOR J = FIRST TO LAST
D = RND
A1(I, J) = D
A2(I, J) = D
NEXT
NEXT
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB CONSOLEOUTPUT(WHICHTIME AS BYTE, T AS DOUBLE)
LOCAL SO AS STRING
LOCAL SN AS STRING
LOCAL ST AS STRING
SN = STR$(%N)
ST = FORMAT$(T, "0000.000")
SELECT CASE WHICHTIME
CASE 1
SO = "Inverting a" & SN & " by" & SN & " matrix the first time,"
PRINT
PRINT SO
PRINT "using PowerBASIC's internal function, ""MAT INV()"".."
PRINT
CASE 2
PRINT "Finished.
PRINT
SO = "elapsed time = " & ST & " seconds"
PRINT SO
PRINT
PRINT "Calculating and writing the first check vector.."
PRINT
CASE 3
PRINT "Finished.
PRINT
SO = "Inverting the" & SN & " by" & SN & " matrix the second time,"
PRINT SO
PRINT "using the coded subroutine, ""INV2()"".."
PRINT
CASE 4
PRINT "Finished.
PRINT
SO = "elapsed time = " & ST & " seconds"
PRINT SO
PRINT
PRINT "Calculating and writing the second check vector.."
PRINT
CASE 5
PRINT "All finished.
PRINT
PRINT "Press ""Enter"" to quit."
PRINT
CASE ELSE
PRINT "Something wrong."
PRINT
END SELECT
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB WRITEFILE(WHICHTIME AS BYTE, V() AS DOUBLE, T AS DOUBLE)
LOCAL FIRST AS LONG
LOCAL LAST AS LONG
LOCAL N AS LONG
LOCAL I AS LONG
LOCAL FN AS STRING
LOCAL S1 AS STRING
LOCAL S2 AS STRING
LOCAL SN AS STRING
LOCAL SO AS STRING
LOCAL ST AS STRING
FIRST = LBOUND(V(1))
LAST = UBOUND(V(1))
N = LAST - FIRST + 1
SN = STR$(N)
ST = FORMAT$(T, "0000.000")
IF (WHICHTIME = 1) THEN
FN = $FN1
SO = "PowerBASIC's internal function, ""MAT INV()""."
ELSE
FN = $FN2
SO = "the coded subroutine, ""INV2()""."
END IF
OPEN FN FOR OUTPUT AS #1
S1 = "FILE = """ & FN & """
PRINT#1, S1
S1 = DATE & ", " & TIME & "."
PRINT#1, S1
PRINT#1
S1 = "Inversion of a" & SN & " by" & SN & " matrix,"
PRINT#1, S1
PRINT#1, "filled with uniformly distributed random doubles,"
PRINT#1, "in the range of [0, 1),"
S1 = "using " & SO
PRINT#1, S1
PRINT#1
S1 = "elapsed time = " & ST & " seconds"
PRINT#1, S1
PRINT#1
PRINT#1, "If the inversion was calculated correctly, then every"
PRINT#1, "value shown below should be very close to 1."
PRINT#1
PRINT#1, "Index Value"
FOR I = FIRST TO LAST
S1 = FORMAT$(I, "0000")
S1 = S1 & " "
S2 = FORMAT$(V(I), "0.00000000000000000000")
S1 = S1 & S2
PRINT#1, S1
NEXT
CLOSE #1
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB INV2(A() AS DOUBLE)
'Uses the Gauss-Jordan Method.
'Inverts matrix, A(), "in-place".
LOCAL PIVOT AS LONG
LOCAL ROW AS LONG
LOCAL COL AS LONG
LOCAL MAXROW AS LONG
LOCAL TEST AS DOUBLE
LOCAL COLMAX AS DOUBLE
LOCAL DIVISOR AS DOUBLE
LOCAL FACTOR AS DOUBLE
LOCAL TEMP AS DOUBLE
LOCAL ROWSWITCH AS LONG
LOCAL SWITCHCOUNT AS LONG
LOCAL FIRST AS LONG
LOCAL LAST AS LONG
LOCAL N AS LONG
'---------------------------------------------
FIRST = LBOUND(A(1))
LAST = UBOUND(A(1))
N = LAST - FIRST + 1
DIM ROWSWITCHES(1 TO N, 1 TO 2) AS LONG
SWITCHCOUNT = 0
FOR PIVOT = FIRST TO LAST
COLMAX = 0
MAXROW = PIVOT
'---------------------------------------------
FOR ROW = PIVOT TO LAST
TEST = ABS(A(ROW, PIVOT))
IF( TEST > COLMAX) THEN
COLMAX = TEST
MAXROW = ROW
END IF
NEXT
'---------------------------------------------
IF(MAXROW <> PIVOT) THEN
FOR COL = FIRST TO LAST
TEMP = A(PIVOT, COL)
A(PIVOT, COL) = A(MAXROW, COL)
A(MAXROW, COL) = TEMP
NEXT
SWITCHCOUNT = SWITCHCOUNT + 1
ROWSWITCHES(SWITCHCOUNT, 1) = PIVOT
ROWSWITCHES(SWITCHCOUNT, 2) = MAXROW
END IF
'---------------------------------------------
DIVISOR = A(PIVOT, PIVOT)
A(PIVOT, PIVOT) = 1
FOR COL = FIRST TO LAST
A(PIVOT, COL) = A(PIVOT, COL) / DIVISOR
NEXT
'---------------------------------------------
FOR ROW = FIRST TO LAST
IF(ROW <> PIVOT) THEN
FACTOR = -A(ROW, PIVOT)
A(ROW, PIVOT) = 0
FOR COL = FIRST TO LAST
A(ROW, COL) = A(ROW, COL) + A(PIVOT, COL) * FACTOR
NEXT
END IF
NEXT
NEXT
'---------------------------------------------
FOR ROWSWITCH = SWITCHCOUNT TO 1 STEP -1
FOR ROW = FIRST TO LAST
TEMP = A(ROW, ROWSWITCHES(ROWSWITCH, 1))
A(ROW, ROWSWITCHES(ROWSWITCH, 1)) = A(ROW, ROWSWITCHES(ROWSWITCH, 2))
A(ROW, ROWSWITCHES(ROWSWITCH, 2)) = TEMP
NEXT
NEXT
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
It was made with the PowerBASIC Console Compiler, version 5.
As it is, the program will not compile using the PowerBASIC Windows Compiler.
The program fills an N x N matrix with random doubles in the range of [0, 1),
and inverts it using the PowerBASIC internal function, "MAT INV()".
It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV1.TXT".
If every value of the N-dimensional check vector is very close to 1, then the inversion is correct.
The program then fills the N x N matrix again with the same set of random doubles,
and inverts it using the coded subroutine (in the program), "INV2()".
It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV2.TXT".
If every value of the N-dimensional check vector is very close to 1, then the second inversion is also correct.
The program runs in a console window, and writes its progress in the window, as it executes.
"INV2()", is coded as a subroutine, because the compiler does not permit users to code functions which return arrays.
The program could be modified to compile using the PowerBASIC Windows Compiler. But, I am not sufficiently motivated to do it.
I noticed one interesting phenomenon. Each time the program runs, two check vectors are written to files,
one for the inversion using PowerBASIC's function, "MAT INV()", and the other for the inversion using the coded subroutine, "INV2()".
For every program run, my experience is that the two check vectors are exactly identical to each other.
I ran the program three times for a 1000 x 1000 matrix.
I.F. = PowerBASIC's internal function, "MAT INV()"
C.S. = the program's coded subroutine, "INV2()"
The times were (seconds),
I.F. ***C.S.
105.881 54.896
104.301 54.863
104.918 55.051
I attached the program file below. I called it, "MATINV.TXT".
(The forum will not permit me to attach a file with the extension, "BAS".)
If you download it, then rename it to, "MATINV.BAS", before you compile it.
(If, by chance, an inversion starts before midnight, and finishes after midnight, the elapsed time for it will be wrong (crazily wrong).)
:oops: :x :twisted:
Dan
'************************************************************************************************************
' FILE = "MATINV.BAS"
' Made with the PowerBASIC Console Compiler, version 5.
' As it is, the program will not compile using the PowerBASIC Windows Compiler.
' The program fills an N x N matrix with random doubles in the range of [0, 1),
' and inverts it using the PowerBASIC internal function, "MAT INV()".
' It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV1.TXT".
' If every value of the N-dimensional check vector is very close to 1, then the inversion is correct.
' The program then fills the N x N matrix again with the same set of random doubles,
' and inverts it using the coded subroutine shown below, "INV2()".
' It times the inversion, and then writes the elapsed time, and a check vector to the file, "MATINV2.TXT".
' If every value of the N-dimensional check vector is very close to 1, then the second inversion is also correct.
' "INV2()", is coded as a subroutine, because the compiler does not permit users to code functions which return arrays.
' The program could be modified to compile using the PowerBASIC Windows Compiler. But, I am not sufficiently motivated to do it.
' I noticed one interesting phenomenon. Each time the program runs, two check vectors are written to files,
' one for the inversion using PowerBASIC's function, "MAT INV()", and the other for the inversion using the coded subroutine, "INV2()".
' For every program run, my experience is that the two check vectors are exactly identical to each other.
'************************************************************************************************************
#COMPILE EXE
#DIM ALL
'Set the size of the N x N matrix to invert, on the next line.
%N = 1000
$FN1 = "MATINV1.TXT"
$FN2 = "MATINV2.TXT"
GLOBAL DATE AS STRING
GLOBAL TIME AS STRING
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
FUNCTION PBMAIN() AS LONG
DIM T0 AS DOUBLE
DIM T1 AS DOUBLE
DIM T2 AS DOUBLE
DIM TT AS DOUBLE
DIM A0(1 TO %N, 1 TO %N) AS DOUBLE
DIM AI(1 TO %N, 1 TO %N) AS DOUBLE
DIM ID(1 TO %N, 1 TO %N) AS DOUBLE
DIM VA(1 TO %N) AS DOUBLE
DIM VB(1 TO %N) AS DOUBLE
'---------------------------------------------
DATE = DATE$
TIME = TIME$
T0 = TIMER
'---------------------------------------------
CALL CONSOLEOUTPUT(1, TT)
RANDOMIZE T0
CALL INITIALIZEARRAYS(A0(), AI(), VA())
T1 = TIMER
MAT AI() = INV(A0())
T2 = TIMER
TT = T2 - T1
CALL CONSOLEOUTPUT(2, TT)
MAT ID = A0 * AI
MAT VB = ID * VA
CALL WRITEFILE(1, VB(), TT)
CALL CONSOLEOUTPUT(3, TT)
'---------------------------------------------
RANDOMIZE T0
CALL INITIALIZEARRAYS(A0(), AI(), VA())
T1 = TIMER
CALL INV2(AI())
T2 = TIMER
TT = T2 - T1
CALL CONSOLEOUTPUT(4, TT)
MAT ID = A0 * AI
MAT VB = ID * VA
CALL WRITEFILE(2, VB(), TT)
'---------------------------------------------
CALL CONSOLEOUTPUT(5, TT)
WAITKEY$
END FUNCTION
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB INITIALIZEARRAYS(A1() AS DOUBLE, A2() AS DOUBLE, V() AS DOUBLE)
LOCAL FIRST AS LONG
LOCAL LAST AS LONG
LOCAL N AS LONG
LOCAL I AS WORD
LOCAL J AS WORD
LOCAL D AS DOUBLE
FIRST = LBOUND(A1(1))
LAST = UBOUND(A2(1))
N = LAST - FIRST + 1
FOR I = FIRST TO LAST
V(I) = 1
FOR J = FIRST TO LAST
D = RND
A1(I, J) = D
A2(I, J) = D
NEXT
NEXT
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB CONSOLEOUTPUT(WHICHTIME AS BYTE, T AS DOUBLE)
LOCAL SO AS STRING
LOCAL SN AS STRING
LOCAL ST AS STRING
SN = STR$(%N)
ST = FORMAT$(T, "0000.000")
SELECT CASE WHICHTIME
CASE 1
SO = "Inverting a" & SN & " by" & SN & " matrix the first time,"
PRINT SO
PRINT "using PowerBASIC's internal function, ""MAT INV()"".."
CASE 2
PRINT "Finished.
SO = "elapsed time = " & ST & " seconds"
PRINT SO
PRINT "Calculating and writing the first check vector.."
CASE 3
PRINT "Finished.
SO = "Inverting the" & SN & " by" & SN & " matrix the second time,"
PRINT SO
PRINT "using the coded subroutine, ""INV2()"".."
CASE 4
PRINT "Finished.
SO = "elapsed time = " & ST & " seconds"
PRINT SO
PRINT "Calculating and writing the second check vector.."
CASE 5
PRINT "All finished.
PRINT "Press ""Enter"" to quit."
CASE ELSE
PRINT "Something wrong."
END SELECT
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB WRITEFILE(WHICHTIME AS BYTE, V() AS DOUBLE, T AS DOUBLE)
LOCAL FIRST AS LONG
LOCAL LAST AS LONG
LOCAL N AS LONG
LOCAL I AS LONG
LOCAL FN AS STRING
LOCAL S1 AS STRING
LOCAL S2 AS STRING
LOCAL SN AS STRING
LOCAL SO AS STRING
LOCAL ST AS STRING
FIRST = LBOUND(V(1))
LAST = UBOUND(V(1))
N = LAST - FIRST + 1
SN = STR$(N)
ST = FORMAT$(T, "0000.000")
IF (WHICHTIME = 1) THEN
FN = $FN1
SO = "PowerBASIC's internal function, ""MAT INV()""."
ELSE
FN = $FN2
SO = "the coded subroutine, ""INV2()""."
END IF
OPEN FN FOR OUTPUT AS #1
S1 = "FILE = """ & FN & """
PRINT#1, S1
S1 = DATE & ", " & TIME & "."
PRINT#1, S1
PRINT#1
S1 = "Inversion of a" & SN & " by" & SN & " matrix,"
PRINT#1, S1
PRINT#1, "filled with uniformly distributed random doubles,"
PRINT#1, "in the range of [0, 1),"
S1 = "using " & SO
PRINT#1, S1
PRINT#1
S1 = "elapsed time = " & ST & " seconds"
PRINT#1, S1
PRINT#1
PRINT#1, "If the inversion was calculated correctly, then every"
PRINT#1, "value shown below should be very close to 1."
PRINT#1
PRINT#1, "Index Value"
FOR I = FIRST TO LAST
S1 = FORMAT$(I, "0000")
S1 = S1 & " "
S2 = FORMAT$(V(I), "0.00000000000000000000")
S1 = S1 & S2
PRINT#1, S1
NEXT
CLOSE #1
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************
SUB INV2(A() AS DOUBLE)
'Uses the Gauss-Jordan Method.
'Inverts matrix, A(), "in-place".
LOCAL PIVOT AS LONG
LOCAL ROW AS LONG
LOCAL COL AS LONG
LOCAL MAXROW AS LONG
LOCAL TEST AS DOUBLE
LOCAL COLMAX AS DOUBLE
LOCAL DIVISOR AS DOUBLE
LOCAL FACTOR AS DOUBLE
LOCAL TEMP AS DOUBLE
LOCAL ROWSWITCH AS LONG
LOCAL SWITCHCOUNT AS LONG
LOCAL FIRST AS LONG
LOCAL LAST AS LONG
LOCAL N AS LONG
'---------------------------------------------
FIRST = LBOUND(A(1))
LAST = UBOUND(A(1))
N = LAST - FIRST + 1
DIM ROWSWITCHES(1 TO N, 1 TO 2) AS LONG
SWITCHCOUNT = 0
FOR PIVOT = FIRST TO LAST
COLMAX = 0
MAXROW = PIVOT
'---------------------------------------------
FOR ROW = PIVOT TO LAST
TEST = ABS(A(ROW, PIVOT))
IF( TEST > COLMAX) THEN
COLMAX = TEST
MAXROW = ROW
END IF
NEXT
'---------------------------------------------
IF(MAXROW <> PIVOT) THEN
FOR COL = FIRST TO LAST
TEMP = A(PIVOT, COL)
A(PIVOT, COL) = A(MAXROW, COL)
A(MAXROW, COL) = TEMP
NEXT
SWITCHCOUNT = SWITCHCOUNT + 1
ROWSWITCHES(SWITCHCOUNT, 1) = PIVOT
ROWSWITCHES(SWITCHCOUNT, 2) = MAXROW
END IF
'---------------------------------------------
DIVISOR = A(PIVOT, PIVOT)
A(PIVOT, PIVOT) = 1
FOR COL = FIRST TO LAST
A(PIVOT, COL) = A(PIVOT, COL) / DIVISOR
NEXT
'---------------------------------------------
FOR ROW = FIRST TO LAST
IF(ROW <> PIVOT) THEN
FACTOR = -A(ROW, PIVOT)
A(ROW, PIVOT) = 0
FOR COL = FIRST TO LAST
A(ROW, COL) = A(ROW, COL) + A(PIVOT, COL) * FACTOR
NEXT
END IF
NEXT
NEXT
'---------------------------------------------
FOR ROWSWITCH = SWITCHCOUNT TO 1 STEP -1
FOR ROW = FIRST TO LAST
TEMP = A(ROW, ROWSWITCHES(ROWSWITCH, 1))
A(ROW, ROWSWITCHES(ROWSWITCH, 1)) = A(ROW, ROWSWITCHES(ROWSWITCH, 2))
A(ROW, ROWSWITCHES(ROWSWITCH, 2)) = TEMP
NEXT
NEXT
END SUB
'************************************************************************************************************
'************************************************************************************************************
'************************************************************************************************************