LU decomposition: Difference between revisions

Content added Content deleted
(D implementation)
(→‎Tcl: Added implementation)
Line 390: Line 390:
[0, 1, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1]]</pre>
[0, 0, 0, 1]]</pre>

=={{header|Tcl}}==
<lang tcl>package require Tcl 8.5

namespace eval matrix {
namespace path {::tcl::mathfunc ::tcl::mathop}
proc I {order} {
set m [lrepeat $order [lrepeat $order 0]]
for {set i 0} {$i < $order} {incr i} {
lset m $i $i 1
}
return $m
}
proc pivotize {matrix} {
set n [llength $matrix]
set p [I $n]
for {set j 0} {$j < $n} {incr j} {
set max [lindex $matrix $j $j]
set row $j
for {set i $j} {$i < $n} {incr i} {
if {[lindex $matrix $i $j] > $max} {
set max [lindex $matrix $i $j]
set row $i
}
}
if {$j != $row} {
set tmp [lindex $p $j]
lset p $j [lindex $p $row]
lset p $row $tmp
}
}
return $p
}

# Decomposes a square matrix A by PA=LU and returns L, U and P
proc luDecompose {A} {
set n [llength $A]
set L [lrepeat $n [lrepeat $n 0]]
set U $L
set P [pivotize $A]
set A [multiply $P $A]

for {set j 0} {$j < $n} {incr j} {
lset L $j $j 1
for {set i 0} {$i <= $j} {incr i} {
lset U $i $j [- [lindex $A $i $j] [SumMul $L $U $i $j $i]]
}
for {set i $j} {$i < $n} {incr i} {
set sum [SumMul $L $U $i $j $j]
lset L $i $j [/ [- [lindex $A $i $j] $sum] [lindex $U $j $j]]
}
}

return [list $L $U $P]
}

# Helper that makes inner loop nicer; multiplies column and row,
# possibly partially...
proc SumMul {A B i j kmax} {
set s 0.0
for {set k 0} {$k < $kmax} {incr k} {
set s [+ $s [* [lindex $A $i $k] [lindex $B $k $j]]]
}
return $s
}

# Code adapted from Matrix_multiplication and Matrix_transposition tasks
proc size {m} {
set rows [llength $m]
set cols [llength [lindex $m 0]]
return [list $rows $cols]
}
proc multiply {a b} {
lassign [size $a] a_rows a_cols
lassign [size $b] b_rows b_cols
if {$a_cols != $b_rows} {
error "incompatible sizes: a($a_rows, $a_cols), b($b_rows, $b_cols)"
}
set temp [lrepeat $a_rows [lrepeat $b_cols 0]]
for {set i 0} {$i < $a_rows} {incr i} {
for {set j 0} {$j < $b_cols} {incr j} {
lset temp $i $j [SumMul $a $b $i $j $a_cols]
}
}
return $temp
}

proc Widest {m fmt} {
lassign [size $m] rows cols
set max [lrepeat $cols 0]
foreach row $m {
for {set j 0} {$j < $cols} {incr j} {
set s [format $fmt [lindex $row $j]]
lset max $j [max [lindex $max $j] [string length $s]]
}
}
return $max
}
proc print {matrix {fmt "%s"}} {
set max [Widest $matrix $fmt]
lassign [size $matrix] rows cols
foreach row $matrix {
foreach val $row width $max {
puts -nonewline [format "%*s " $width [format $fmt $val]]
}
puts ""
}
}
}

# Demonstration helper
proc demo {A} {
lassign [matrix::luDecompose $A] L U P
foreach v {A L U P} {
upvar 0 $v matrix
puts "${v}:"
matrix::print $matrix %.5g
if {$v ne "P"} {puts "---------------------------------"}
}
}
demo {{1 3 5} {2 4 7} {1 1 0}}
puts "================================="
demo {{11 9 24 2} {1 5 2 6} {3 17 18 1} {2 5 7 1}}</lang>
<pre>
A:
1 3 5
2 4 7
1 1 0
---------------------------------
L:
1 0 0
0.5 1 0
0.5 -1 1
---------------------------------
U:
2 4 7
0 1 1.5
0 0 -2
---------------------------------
P:
0 1 0
1 0 0
0 0 1
=================================
A:
11 9 24 2
1 5 2 6
3 17 18 1
2 5 7 1
---------------------------------
L:
1 0 0 0
0.27273 1 0 0
0.090909 0.2875 1 0
0.18182 0.23125 0.0035971 1
---------------------------------
U:
11 9 24 2
0 14.545 11.455 0.45455
0 0 -3.475 5.6875
0 0 0 0.51079
---------------------------------
P:
1 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
</pre>