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

'************************************************************************************************************

'************************************************************************************************************

'************************************************************************************************************