@@ -84,13 +84,46 @@ type LinearAlgebra =
8484
8585 Matrix( m, n, qData), r
8686
87+ ///// <summary>Forward substitute to solve L * x = y</summary>
88+ ///// <remarks>L is lower triangular</remarks>
89+ //static member inline forwardSubstitute<'T when 'T :> Numerics.INumber<'T>
90+ // and 'T : (new: unit -> 'T)
91+ // and 'T : struct
92+ // and 'T : comparison
93+ // and 'T :> ValueType>
94+ // (L : Matrix<'T>)
95+ // (y : Vector<'T>) : Vector<'T> =
96+
97+ // let n = L.NumRows
98+
99+ // if L.NumCols <> n || y.Length <> n then
100+ // invalidArg "dimensions" "L must be square and match the length of y"
101+
102+ // let x = Array.zeroCreate<'T> n
103+ // let cols = L.NumCols
104+ // let lData = L.Data
105+
106+ // // Again, scalar version; easy to SIMD the inner sum later
107+ // for i = 0 to n - 1 do
108+ // let mutable s = y.[i]
109+ // let rowOffset = i * cols
110+ // for j = 0 to i - 1 do
111+ // s <- s - lData.[rowOffset + j] * x.[j]
112+ // let diag = lData.[rowOffset + i]
113+ // if diag = 'T.Zero then
114+ // invalidArg $"Matrix[{i},{i}]" "Diagonal element is zero. Cannot divide."
115+ // x.[i] <- s / diag
116+
117+ // x
118+
119+
87120 /// <summary >Forward substitute to solve L * x = y</summary >
88121 /// <remarks >L is lower triangular</remarks >
89122 static member inline forwardSubstitute < 'T when 'T :> Numerics.INumber < 'T >
90- and 'T : ( new : unit -> 'T )
91- and 'T : struct
92- and 'T : comparison
93- and 'T :> ValueType >
123+ and 'T : ( new : unit -> 'T )
124+ and 'T : struct
125+ and 'T : comparison
126+ and 'T :> ValueType >
94127 ( L : Matrix < 'T >)
95128 ( y : Vector < 'T >) : Vector < 'T > =
96129
@@ -103,15 +136,26 @@ type LinearAlgebra =
103136 let cols = L.NumCols
104137 let lData = L.Data
105138
106- // Again, scalar version; easy to SIMD the inner sum later
139+ // Forward substitution:
140+ // x[i] <- ( y[i] - sum_{j=0..i-1}(L[i,j] * x[j]) ) / L[i,i]
107141 for i = 0 to n - 1 do
108142 let mutable s = y.[ i]
109143 let rowOffset = i * cols
110- for j = 0 to i - 1 do
111- s <- s - lData.[ rowOffset + j] * x.[ j]
144+ let len = i // number of entries below diagonal in this row (0..i-1)
145+
146+ if len > 0 then
147+ // row slice: L[i, 0 .. i-1]
148+ let rowSpan = ReadOnlySpan< 'T>( lData, rowOffset, len)
149+ // x slice: x[0 .. i-1]
150+ let xSpan = ReadOnlySpan< 'T>( x, 0 , len)
151+
152+ let dot = SpanMath.dot( rowSpan, xSpan)
153+ s <- s - dot
154+
112155 let diag = lData.[ rowOffset + i]
113156 if diag = 'T.Zero then
114157 invalidArg $" Matrix[{i},{i}]" " Diagonal element is zero. Cannot divide."
158+
115159 x.[ i] <- s / diag
116160
117161 x
0 commit comments