Skip to content

Commit de30988

Browse files
committed
Added pseudoinverseOfDiagonal: and refactored the tests
1 parent e7b8e0c commit de30988

File tree

5 files changed

+147
-138
lines changed

5 files changed

+147
-138
lines changed

src/Math-Numerical/PMLeastSquares.class.st

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@ Class {
44
#category : #'Math-Numerical'
55
}
66

7+
{ #category : #'as yet unclassified' }
8+
PMLeastSquares >> pseudoinverseOfDiagonal: aMatrix [
9+
"To get pseudoinverse of a diagonal rectangular matrix, we take reciprocal of any no-zero element of the main diagonal, leaving all zeros in place. Then we transpose the matrix."
10+
11+
| pseudoinverse diagonalSize |
12+
13+
"Rows become columns and columns become rows because we transpose"
14+
pseudoinverse := PMMatrix
15+
zerosRows: aMatrix numberOfColumns
16+
cols: aMatrix numberOfRows.
17+
18+
"The size of the main diagonal of a rectangular matrix is its smallest dimension"
19+
diagonalSize := aMatrix numberOfRows min: aMatrix numberOfColumns.
20+
21+
"Inverting the elements on the main diaginal"
22+
1 to: diagonalSize do: [ :i |
23+
pseudoinverse at: i at: i put: ((aMatrix at: i at: i) = 0
24+
ifTrue: [ 0 ] ifFalse: [ 1 / (aMatrix at: i at: i) ]) ].
25+
26+
^ pseudoinverse
27+
]
28+
729
{ #category : #'as yet unclassified' }
830
PMLeastSquares >> solveMatrixA: aMatrix matrixB: aMatrixOrVector [
931

@@ -22,7 +44,6 @@ PMLeastSquares >> solveMatrixA: aMatrix matrixB: aMatrixOrVector [
2244
s := svd diagonalSingularValueMatrix.
2345
v := svd rightSingularMatrix.
2446

25-
pseudoinverse := s inverse.
26-
47+
pseudoinverse := self pseudoinverseOfDiagonal: s.
2748
^ v * pseudoinverse * u transpose * aMatrixOrVector
2849
]

src/Math-Tests-Numerical/PMLeastSquaresFixture.class.st

Lines changed: 0 additions & 54 deletions
This file was deleted.

src/Math-Tests-Numerical/PMLeastSquaresFixtureIntelFortran.class.st

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/Math-Tests-Numerical/PMLeastSquaresFixtureSmallOneSolution.class.st

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/Math-Tests-Numerical/PMLeastSquaresTest.class.st

Lines changed: 124 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,141 @@ PMLeastSquaresTest >> setUp [
1717
]
1818

1919
{ #category : #tests }
20-
PMLeastSquaresTest >> testSolveIntelFortran [
20+
PMLeastSquaresTest >> testPseudoinverseOfDiagonalSquareMatrix [
21+
22+
| matrix expectedInverse inverse |
23+
24+
matrix := PMMatrix rows: #(
25+
(2 0 0 0)
26+
(0 1 0 0)
27+
(0 0 -3 0)
28+
(0 0 0 -1)).
29+
30+
expectedInverse := PMMatrix rows: {
31+
{ 1/2 . 0 . 0 . 0 } .
32+
{ 0 . 1 . 0 . 0 } .
33+
{0 . 0 . -1/3 . 0} .
34+
{0 . 0 . 0 . -1 }}.
35+
36+
inverse := leastSquares pseudoinverseOfDiagonal: matrix.
37+
self assert: inverse closeTo: expectedInverse.
38+
]
39+
40+
{ #category : #tests }
41+
PMLeastSquaresTest >> testPseudoinverseOfDiagonalSquareMatrixWithZeros [
42+
43+
| matrix expectedInverse inverse |
44+
45+
matrix := PMMatrix rows: #(
46+
(2 0 0 0)
47+
(0 1 0 0)
48+
(0 0 0 0)
49+
(0 0 0 0)).
50+
51+
expectedInverse := PMMatrix rows: #(
52+
(0.5 0 0 0)
53+
(0 1 0 0)
54+
(0 0 0 0)
55+
(0 0 0 0)).
56+
57+
inverse := leastSquares pseudoinverseOfDiagonal: matrix.
58+
self assert: inverse closeTo: expectedInverse.
59+
]
60+
61+
{ #category : #tests }
62+
PMLeastSquaresTest >> testPseudoinverseOfDiagonalTallMatrix [
2163

22-
| fixture solution |
64+
| matrix expectedInverse inverse |
2365

24-
fixture := PMLeastSquaresFixtureIntelFortran new.
66+
matrix := PMMatrix rows: #(
67+
(2 0 0 0)
68+
(0 1 0 0)
69+
(0 0 -3 0)
70+
(0 0 0 -1)
71+
(0 0 0 0)
72+
(0 0 0 0)).
73+
74+
expectedInverse := PMMatrix rows: {
75+
{ 1/2 . 0 . 0 . 0 . 0 . 0 } .
76+
{ 0 . 1 . 0 . 0 . 0 . 0 } .
77+
{0 . 0 . -1/3 . 0 . 0 . 0 } .
78+
{0 . 0 . 0 . -1 . 0 . 0 }}.
79+
80+
inverse := leastSquares pseudoinverseOfDiagonal: matrix.
81+
self assert: inverse closeTo: expectedInverse.
82+
]
83+
84+
{ #category : #tests }
85+
PMLeastSquaresTest >> testPseudoinverseOfDiagonalWideMatrix [
86+
87+
| matrix expectedInverse inverse |
88+
89+
matrix := PMMatrix rows: #(
90+
(2 0 0 0 0 0)
91+
(0 1 0 0 0 0)
92+
(0 0 -3 0 0 0)
93+
(0 0 0 -1 0 0)).
94+
95+
expectedInverse := PMMatrix rows: {
96+
{ 1/2 . 0 . 0 . 0 } .
97+
{ 0 . 1 . 0 . 0 } .
98+
{0 . 0 . -1/3 . 0} .
99+
{0 . 0 . 0 . -1 } .
100+
{0 . 0 . 0 . 0 } .
101+
{0 . 0 . 0 . 0 }}.
102+
103+
inverse := leastSquares pseudoinverseOfDiagonal: matrix.
104+
self assert: inverse closeTo: expectedInverse.
105+
]
106+
107+
{ #category : #tests }
108+
PMLeastSquaresTest >> testSolveIntelFortran [
109+
"An example of least squares system (AX = B) taken from Intel DGELSD Example Program in Fortran:
110+
https://www.intel.com/content/www/us/en/develop/documentation/onemkl-lapack-examples/top/least-squares-and-eigenvalue-problems/linear-least-squares-lls-problems/gelsd-function/dgelsd-example/dgelsd-example-fortran.html"
111+
| matrixA matrixB expectedSolution solution |
112+
113+
matrixA := PMMatrix rows: #(
114+
( 0.12 -8.19 7.69 -2.26 -4.71)
115+
(-6.91 2.22 -5.12 -9.08 9.96)
116+
(-3.33 -8.94 -6.72 -4.40 -9.98)
117+
( 3.97 3.33 -2.74 -7.92 -3.20)).
118+
119+
matrixB := PMMatrix rows: #(
120+
(7.30 0.47 -6.28)
121+
(1.33 6.58 -3.42)
122+
(2.68 -1.71 3.46)
123+
(-9.62 -0.79 0.41)).
124+
125+
expectedSolution := PMMatrix rows: #(
126+
(-0.69 -0.24 0.06)
127+
(-0.80 -0.08 0.21)
128+
( 0.38 0.12 -0.65)
129+
( 0.29 -0.24 0.42)
130+
( 0.29 0.35 -0.30)).
25131

26132
solution := leastSquares
27-
solveMatrixA: fixture matrixA
28-
matrixB: fixture matrixB.
133+
solveMatrixA: matrixA
134+
matrixB: matrixB.
29135

30-
self assert: solution closeTo: fixture matrixX.
136+
self assert: solution closeTo: expectedSolution.
31137
]
32138

33139
{ #category : #tests }
34140
PMLeastSquaresTest >> testSolveSmallOneSolution [
35-
36-
| fixture solution |
141+
"Small example of least squares system (AX = B) with one solution taken from here: https://textbooks.math.gatech.edu/ila/least-squares.html"
142+
| matrixA vectorB expectedSolution solution |
37143

38-
fixture := PMLeastSquaresFixtureSmallOneSolution new.
144+
matrixA := PMMatrix rows: #(
145+
(0 1.1)
146+
(1 0)
147+
(0 -0.2)).
148+
149+
vectorB := #(1.1 -1.1 -0.2) asPMVector.
150+
expectedSolution := #(-1.1 1) asPMVector.
39151

40152
solution := leastSquares
41-
solveMatrixA: fixture matrixA
42-
matrixB: fixture matrixB.
153+
solveMatrixA: matrixA
154+
matrixB: vectorB.
43155

44-
self assert: solution closeTo: fixture matrixX.
156+
self assert: solution closeTo: expectedSolution.
45157
]

0 commit comments

Comments
 (0)