Gruß zur Stunde,
da ich durch lineare Algebra viel mit Matrizen zu tun hatte, habe ich mal kurzerhand ein paar Matrizen Funktionen entworfen. Zwar gibt es Eigen4AutoIt schon, allerdings dachte ich mir dass das eine schöne Übung ist. Das primäre Ziel ist es allerdings, einen Matrizenrechner über Restklassenkörpern zu erstellen, da ich keinen wirklich "einfachen" Restklassenkörper-Matrizen Löser fand.
Derzeit sind folgende Funktionen enthalten:
Funktionsbeschreibung
Funktionsname | Funktionsweise / Kurzbeschreibung |
_Matrix_AddColumnToMatrixColumn($aMatrix, $aColumn, $dColumn) | Addiert auf $aMatrix in Spalte $dColumn die 1-spaltige Matrix $aColumn |
_Matrix_AddRowToMatrixRow($aMatrix, $aRow, $dRow) | Addiert auf $aMatrix in Spalte $dRow die 1-zeilige Matrix $aRow |
_Matrix_AddMatrix($aMatrix1, $addMatrix2) | Addiert $aMatrix1 zu $aMatrix2 |
_Matrix_ExtractRow($aMatrix, $mRow) | Extrahiert aus $aMatrix eine 1-zeilige Matrix an Stelle $mRow |
_Matrix_ExtractColumn($aMatrix, $mColumn) | Extrahiert aus $aMatrix eine 1-spaltige Matrix an Stelle $mColumn |
_Matrix_GetCofactorMatrix($aMatrix) | Gibt die Kofaktormatrix von $aMatrix zurück |
_Matrix_GetAdjugateMatrix($aMatrix) | Gibt die (!) Adjunkte (!) von $aMatrix zurück |
_Matrix_GetInverseMatrixWithAdjugate($aMatrix) | Berechnung der Inversen von $aMatrix, falls nicht invertierbar -1 |
_Matrix_GetDeterminantLaPlace($aMatrix) | Bestimmt die Determinante von $aMatrix durch den Laplaceschen Entwicklungssatz |
_Matrix_GetDeterminantGauss($aMatrix) | Bestimmt die Determinante von $aMatrix über die Dreiecksform nach Gauß |
_Matrix_MultiplyRowWithScalar($aMatrix, $mRow, $mScalar) | Multipliziert alle Einträge der Zeile $mRow mit $mScalar in $aMatrix |
_Matrix_MultiplyColumnWithScalar($aMatrix, $mColumn, $mScalar) | Multipliziert alle Einträge der Spalte $mRow mit $mScalar in $aMatrix |
_Matrix_MultiplyWithMatrix($aMartix1, $aMatrix2) | Multipliziert $aMatrix1 mit $aMatrix2 nach $aMatrix1 * $aMatrix2 - ACHTUNG, NICHT KOMMUTATIV! |
_Matrix_RemoveRowAndColumn($aMatrix, $mRow, $mColumn) | Erstellt eine neue Matrix aus $aMatrix ohne die Zeile $mRow und die Spalte $mColumn |
_Matrix_SubstractMatrix($aMatrix1, $aMatrix2) | Subtrahiert $aMatrix2 von $aMatrix1 |
_Matrix_SwapRows($aMatrix, $mRow1, $mRow2) | Vertauschung der Zeilen $mRow1 und $mRow2 von $aMatrix |
_Matrix_SwapColumns($aMatrix, $mColumn1, $mColumn2) | Vertauschung der Zeilen $mColumn1 und $mColumn2 von $aMatrix |
_Matrix_TransposeMatrix($aMatrix) | Transponiert $aMatrix |
Func _Matrix_AddColumnToMatrixColumn($aMatrix, $aColumn, $dColumn)
If (UBound($aMatrix) = UBound($dColumn)) Then
Local $returnMatrix = $aMatrix
For $row = 0 To UBound($aMatrix) - 1 Step 1
$returnMatrix[$row][$dColumn] += $aColumn[$row][0]
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_AddColumnToMatrix
Func _Matrix_AddRowToMatrixRow($aMatrix, $aRow, $dRow)
If (UBound($aMatrix, 2) = UBound($aRow, 2)) Then
Local $returnMatrix = $aMatrix
For $column = 0 To UBound($aMatrix, 2) - 1 Step 1
$returnMatrix[$dRow][$column] += $aRow[0][$column]
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_AddRowToMatrix
Func _Matrix_AddMatrix($aMatrix1, $aMatrix2)
If (UBound($aMatrix1) = UBound($aMatrix2)) And (UBound($aMatrix1, 2) = UBound($aMatrix2, 2)) Then
Local $returnMatrix = $aMatrix1
For $row = 0 To UBound($aMatrix1) - 1 Step 1
For $column = 0 To UBound($aMatrix1, 2) - 1 Step 1
$returnMatrix[$row][$column] += $aMatrix2[$row][$column]
Next
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_AddMatrix
Func _Matrix_ExtractRow($aMatrix, $mRow)
If ($mRow < UBound($aMatrix)) Then
Local $returnRow[1][UBound($aMatrix, 2)]
For $column = 0 To UBound($aMatrix, 2) - 1 Step 1
$returnRow[0][$column] = $aMatrix[$mRow][$column]
Next
Return $returnRow
EndIf
Return -1
EndFunc ;==>_Matrix_ExtractRow
Func _Matrix_ExtractColumn($aMatrix, $mColumn)
If ($mColumn < UBound($aMatrix, 2)) Then
Local $returnColumn[UBound($aMatrix)][1]
For $row = 0 To UBound($aMatrix) - 1 Step 1
$returnColumn[$row][0] = $aMatrix[$row][$mColumn]
Next
Return $returnColumn
EndIf
Return -1
EndFunc ;==>_Matrix_ExtractColumn
Func _Matrix_GetCofactorMatrix($aMatrix)
If UBound($aMatrix) = UBound($aMatrix, 2) Then
Local $returnMatrix[UBound($aMatrix)][UBound($aMatrix)]
For $row = 0 To UBound($aMatrix) - 1 Step 1
For $column = 0 To UBound($aMatrix) - 1 Step 1
$returnMatrix[$row][$column] = (Mod($row + $column, 2) = 0 ? 1 : (-1)) * _Matrix_GetDeterminantGauss(_Matrix_RemoveRowAndColumn($aMatrix, $row, $column))
Next
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_GetCofactorMatrix
Func _Matrix_GetAdjugateMatrix($aMatrix)
Return _Matrix_TransposeMatrix(_Matrix_GetCofactorMatrix($aMatrix))
EndFunc ;==>_Matrix_GetAdjugateMatrix
Func _Matrix_GetDeterminantLaPlace($aMatrix)
If UBound($aMatrix) = UBound($aMatrix, 2) Then
Local $returnDet = 0
If UBound($aMatrix) = 3 Then
Local $tempAdd, $tempSub
For $startColumn = 0 To 2 Step 1
$tempAdd = 1
$tempSub = 1
For $row = 0 To 2 Step 1
$tempAdd *= $aMatrix[$row][Mod($startColumn + $row, 3)]
$tempSub *= $aMatrix[2 - $row][Mod($startColumn + $row, 3)]
Next
$returnDet += $tempAdd - $tempSub
Next
Return $returnDet
EndIf
If UBound($aMatrix) = 2 Then
Return $aMatrix[0][0] * $aMatrix[1][1] - $aMatrix[1][0] * $aMatrix[0][1]
EndIf
If UBound($aMatrix) = 1 Then
Return $aMatrix[0]
EndIf
;Matrix Größer 3 -> Laplace Entwicklungssatz
For $column = 0 To UBound($aMatrix) - 1 Step 1
$returnDet += (Mod($column, 2) = 0 ? 1 : (-1)) * $aMatrix[0][$column] * _Matrix_GetDeterminantLaPlace(_Matrix_RemoveRowAndColumn($aMatrix, 0, $column))
Next
Return $returnDet
EndIf
Return 0
EndFunc ;==>_Matrix_GetDeterminantLaPlace
Func _Matrix_GetInverseMatrixWithAdjugate($aMatrix)
Local $Determinant = _Matrix_GetDeterminantGauss($aMatrix)
If $Determinant = 0 Then Return -1
Return _Matrix_MultiplyWithScalar(_Matrix_GetAdjugateMatrix($aMatrix), 1 / $Determinant)
EndFunc ;==>_Matrix_GetInverseMatrix
Func _Matrix_GetDeterminantGauss($aMatrix)
If UBound($aMatrix) = UBound($aMatrix, 2) Then
Local $determinantMultiplier = 1
Local $signum = 0
Local $returnMatrix = $aMatrix
Local $workingColumn = 0
Local $addRow, $addRowCopy
Local $isZero = False
For $workingRow = 0 To UBound($returnMatrix) - 1 Step 1
$isZero = True
For $actualRow = $workingRow To UBound($returnMatrix) - 1 Step 1
If ($returnMatrix[$actualRow][$workingColumn] <> 0) Then
If ($actualRow <> $workingRow) Then
$signum += 1
$returnMatrix = _Matrix_SwapRows($returnMatrix, $actualRow, $workingRow)
EndIf
$determinantMultiplier *= $returnMatrix[$workingRow][$workingColumn]
$returnMatrix = _Matrix_MultiplyRowWithScalar($returnMatrix, $workingRow, 1 / $returnMatrix[$workingRow][$workingColumn])
$isZero = False
ExitLoop
EndIf
Next
If ($isZero) Then Return 0
$addRow = _Matrix_ExtractRow($returnMatrix, $workingRow)
$addRowCopy = $addRow
For $actualRow = $workingRow + 1 To UBound($returnMatrix) - 1 Step 1
If ($returnMatrix[$actualRow][$workingColumn] <> 0) Then
$addRow = _Matrix_MultiplyWithScalar($addRow, (-1) * $returnMatrix[$actualRow][$workingColumn])
$returnMatrix = _Matrix_AddRowToMatrixRow($returnMatrix, $addRow, $actualRow)
$addRow = $addRowCopy
EndIf
Next
$workingColumn += 1
Next
Return $determinantMultiplier * (Mod($signum, 2) = 1 ? -1 : 1)
EndIf
Return 0
EndFunc ;==>_Matrix_GetDeterminantGauss
Func _Matrix_MultiplyRowWithScalar($aMatrix, $mRow, $mScalar)
If $mRow < UBound($aMatrix) Then
Local $returnMatrix = $aMatrix
For $column = 0 To UBound($aMatrix, 2) - 1 Step 1
If ($returnMatrix[$mRow][$column] <> 0) Then
$returnMatrix[$mRow][$column] *= $mScalar
EndIf
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_MultiplyRowWithScalar
Func _Matrix_MultiplyColumnWithScalar($aMatrix, $mColumn, $mScalar)
If $mColumn <= UBound($aMatrix, 2) - 1 Then
Local $returnMatrix = $aMatrix
For $row = 0 To UBound($aMatrix) - 1 Step 1
If ($returnMatrix[$row][$mColumn] <> 0) Then
$returnMatrix[$row][$mColumn] *= $mScalar
EndIf
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_MultiplyColumnWithScalar
Func _Matrix_MultiplyWithScalar($aMatrix, $mScalar)
Local $returnMatrix = $aMatrix
For $row = 0 To UBound($aMatrix) - 1 Step 1
For $column = 0 To UBound($aMatrix, 2) - 1 Step 1
If ($returnMatrix[$row][$column] <> 0) Then
$returnMatrix[$row][$column] *= $mScalar
EndIf
Next
Next
Return $returnMatrix
EndFunc ;==>_Matrix_MultiplyWithScalar
Func _Matrix_MultiplyWithMatrix($aMatrix1, $aMatrix2)
If (UBound($aMatrix1, 2) = UBound($aMatrix2)) Then
Local $returnMatrix[UBound($aMatrix1)][UBound($aMatrix2, 2)]
For $newRow = 0 To UBound($returnMatrix) - 1 Step 1
For $newColumn = 0 To UBound($returnMatrix, 2) - 1 Step 1
Local $newValue = 0
For $i = 0 To UBound($aMatrix1) - 1 Step 1
$newValue += $aMatrix1[$newRow][$i] * $aMatrix2[$i][$newColumn]
Next
If ($newValue = -(0.0)) Then $newValue = 0
$returnMatrix[$newRow][$newColumn] = $newValue
Next
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_MultiplyWithMatrix
Func _Matrix_RemoveRowAndColumn($aMatrix, $mRow, $mColumn)
If ($mRow < UBound($aMatrix)) And ($mColumn < UBound($aMatrix, 2)) Then
Local $returnMatrix[UBound($aMatrix) - 1][UBound($aMatrix, 2) - 1]
For $row = 0 To UBound($returnMatrix) - 1 Step 1
For $column = 0 To UBound($returnMatrix, 2) - 1 Step 1
$returnMatrix[$row][$column] = $aMatrix[$row + ($row >= $mRow ? 1 : 0)][$column + ($column >= $mColumn ? 1 : 0)]
Next
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_RemoveRowAndColumn
Func _Matrix_SubstractMatrix($aMatrix1, $aMatrix2)
Return _Matrix_AddMatrix($aMatrix1, _Matrix_MultiplyWithScalar($aMatrix2, (-1)))
EndFunc ;==>_Matrix_SubstractMatrix
Func _Matrix_SwapRows($aMatrix, $mRow1, $mRow2)
If ($mRow1 = $mRow2) Then Return $aMatrix
If ($mRow1 < UBound($aMatrix)) And ($mRow2 < UBound($aMatrix)) Then
Local $returnMatrix = $aMatrix
Local $tempVal = 0
For $column = 0 To UBound($aMatrix, 2) - 1 Step 1
$tempVal = $aMatrix[$mRow1][$column]
$returnMatrix[$mRow1][$column] = $returnMatrix[$mRow2][$column]
$returnMatrix[$mRow2][$column] = $tempVal
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_SwapRows
Func _Matrix_SwapColumns($aMatrix, $mColumn1, $mColumn2)
If ($mColumn1 < UBound($aMatrix, 2)) And ($mColumn2 < UBound($aMatrix, 2)) Then
Local $returnMatrix = $aMatrix
Local $tempVal = 0
For $row = 0 To UBound($aMatrix) - 1 Step 1
$tempVal = $returnMatrix[$row][$mColumn1]
$returnMatrix[$row][$mColumn1] = $returnMatrix[$row][$mColumn2]
$returnMatrix[$row][$mColumn2] = $tempVal
Next
Return $returnMatrix
EndIf
Return -1
EndFunc ;==>_Matrix_SwapColumns
Func _Matrix_TransposeMatrix($aMatrix)
Local $returnMatrix[UBound($aMatrix, 2)][UBound($aMatrix)]
For $row = 0 To UBound($aMatrix) - 1 Step 1
For $column = 0 To UBound($aMatrix, 2) - 1 Step 1
$returnMatrix[$column][$row] = $aMatrix[$row][$column]
Next
Next
Return $returnMatrix
EndFunc ;==>_Matrix_TransposeMatrix
Alles anzeigen
Rückgabewerte:
Alle Funktionen sind Call-By-Value geschrieben, das ist sinniger, falls man mit den Matrizen mehrere Operationen durchführen will.
Die Rückgabewerte werde ich nochmal überarbeiten, derzeit wird -1 zurück gegeben, falls eine Operation nicht erlaubt ist (z.B. unterschiedlich dimensionierte Matrizen addieren / subtrahieren, ...), bzw. die Matrix / Determinante welche ausgerechnet wurde.
Da die Klausurzeit jetzt los geht, werde ich die UDF erst in den Semesterferien erweitern, geplant ist noch:
- Gauß-Jordan Algorithmus zum lösen eines LGS
- Rang einer Matrix bestimmen
- Rechnen über Restklassekörpern
- Auskommentierung des Codes
(- Einen Matrix-Rechner mit GUI)
(- Rechnen über komplexen Zahlen)
--- Was euch noch so einfällt
Falls Fehler gefunden werden bitte sofort mitteilen, ich habe die Funktionen simultan mit einem online Matrix-Solver überprüft, aber vor dem Fehlerteufel ist man ja nie sicher.
----------------------------------------
Mal ein kleiner "Benchmark" Laplace gegenüber Gauß-Algorithmus.
Bei n <= 4 ist Laplace bis dato noch schneller gewesen (da Regel von Sarrus eingepflegt, sonst wäre er es wohl nicht). Deshalb mal eine 6x6 Matrix gebaut und diese durchrechnen lassen.
1 | -5 | 9 | -13 | 7 | 1 |
-2 | 6 | -10 | 12 | 1 | 3 |
4 | -8 | 14 | -16 | -1 | 5 |
-3 | 7 | -11 | 15 | 8 | 7 |
1 | 0 | -1 | 3 | 4 | 11 |
-1 | -2 | -3 | -4 | -5 | -6 |
Die Determinante dieser Matrix ließ ich 100.000 Mal berechnen, einmal mit Gauß und einmal mit Laplace.
Fazit:
Laplace benötigte 1128541 Millisekunden, also rund 1128 Sekunden, was 18 Minuten und 48 Sekunden entspricht.
Gauß dagegen benötigte "gerademal" 81034 Millisekunden, was in etwa 81 Sekunden entspricht.