triangular.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. // Copyright ©2015 The Gonum Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package mat
  5. import (
  6. "math"
  7. "gonum.org/v1/gonum/blas"
  8. "gonum.org/v1/gonum/blas/blas64"
  9. "gonum.org/v1/gonum/lapack/lapack64"
  10. )
  11. var (
  12. triDense *TriDense
  13. _ Matrix = triDense
  14. _ allMatrix = triDense
  15. _ denseMatrix = triDense
  16. _ Triangular = triDense
  17. _ RawTriangular = triDense
  18. _ MutableTriangular = triDense
  19. _ NonZeroDoer = triDense
  20. _ RowNonZeroDoer = triDense
  21. _ ColNonZeroDoer = triDense
  22. )
  23. const badTriCap = "mat: bad capacity for TriDense"
  24. // TriDense represents an upper or lower triangular matrix in dense storage
  25. // format.
  26. type TriDense struct {
  27. mat blas64.Triangular
  28. cap int
  29. }
  30. // Triangular represents a triangular matrix. Triangular matrices are always square.
  31. type Triangular interface {
  32. Matrix
  33. // Triangle returns the number of rows/columns in the matrix and its
  34. // orientation.
  35. Triangle() (n int, kind TriKind)
  36. // TTri is the equivalent of the T() method in the Matrix interface but
  37. // guarantees the transpose is of triangular type.
  38. TTri() Triangular
  39. }
  40. // A RawTriangular can return a blas64.Triangular representation of the receiver.
  41. // Changes to the blas64.Triangular.Data slice will be reflected in the original
  42. // matrix, changes to the N, Stride, Uplo and Diag fields will not.
  43. type RawTriangular interface {
  44. RawTriangular() blas64.Triangular
  45. }
  46. // A MutableTriangular can set elements of a triangular matrix.
  47. type MutableTriangular interface {
  48. Triangular
  49. SetTri(i, j int, v float64)
  50. }
  51. var (
  52. _ Matrix = TransposeTri{}
  53. _ Triangular = TransposeTri{}
  54. _ UntransposeTrier = TransposeTri{}
  55. )
  56. // TransposeTri is a type for performing an implicit transpose of a Triangular
  57. // matrix. It implements the Triangular interface, returning values from the
  58. // transpose of the matrix within.
  59. type TransposeTri struct {
  60. Triangular Triangular
  61. }
  62. // At returns the value of the element at row i and column j of the transposed
  63. // matrix, that is, row j and column i of the Triangular field.
  64. func (t TransposeTri) At(i, j int) float64 {
  65. return t.Triangular.At(j, i)
  66. }
  67. // Dims returns the dimensions of the transposed matrix. Triangular matrices are
  68. // square and thus this is the same size as the original Triangular.
  69. func (t TransposeTri) Dims() (r, c int) {
  70. c, r = t.Triangular.Dims()
  71. return r, c
  72. }
  73. // T performs an implicit transpose by returning the Triangular field.
  74. func (t TransposeTri) T() Matrix {
  75. return t.Triangular
  76. }
  77. // Triangle returns the number of rows/columns in the matrix and its orientation.
  78. func (t TransposeTri) Triangle() (int, TriKind) {
  79. n, upper := t.Triangular.Triangle()
  80. return n, !upper
  81. }
  82. // TTri performs an implicit transpose by returning the Triangular field.
  83. func (t TransposeTri) TTri() Triangular {
  84. return t.Triangular
  85. }
  86. // Untranspose returns the Triangular field.
  87. func (t TransposeTri) Untranspose() Matrix {
  88. return t.Triangular
  89. }
  90. func (t TransposeTri) UntransposeTri() Triangular {
  91. return t.Triangular
  92. }
  93. // NewTriDense creates a new Triangular matrix with n rows and columns. If data == nil,
  94. // a new slice is allocated for the backing slice. If len(data) == n*n, data is
  95. // used as the backing slice, and changes to the elements of the returned TriDense
  96. // will be reflected in data. If neither of these is true, NewTriDense will panic.
  97. // NewTriDense will panic if n is zero.
  98. //
  99. // The data must be arranged in row-major order, i.e. the (i*c + j)-th
  100. // element in the data slice is the {i, j}-th element in the matrix.
  101. // Only the values in the triangular portion corresponding to kind are used.
  102. func NewTriDense(n int, kind TriKind, data []float64) *TriDense {
  103. if n <= 0 {
  104. if n == 0 {
  105. panic(ErrZeroLength)
  106. }
  107. panic("mat: negative dimension")
  108. }
  109. if data != nil && len(data) != n*n {
  110. panic(ErrShape)
  111. }
  112. if data == nil {
  113. data = make([]float64, n*n)
  114. }
  115. uplo := blas.Lower
  116. if kind == Upper {
  117. uplo = blas.Upper
  118. }
  119. return &TriDense{
  120. mat: blas64.Triangular{
  121. N: n,
  122. Stride: n,
  123. Data: data,
  124. Uplo: uplo,
  125. Diag: blas.NonUnit,
  126. },
  127. cap: n,
  128. }
  129. }
  130. func (t *TriDense) Dims() (r, c int) {
  131. return t.mat.N, t.mat.N
  132. }
  133. // Triangle returns the dimension of t and its orientation. The returned
  134. // orientation is only valid when n is not empty.
  135. func (t *TriDense) Triangle() (n int, kind TriKind) {
  136. return t.mat.N, t.triKind()
  137. }
  138. func (t *TriDense) isUpper() bool {
  139. return isUpperUplo(t.mat.Uplo)
  140. }
  141. func (t *TriDense) triKind() TriKind {
  142. return TriKind(isUpperUplo(t.mat.Uplo))
  143. }
  144. func isUpperUplo(u blas.Uplo) bool {
  145. switch u {
  146. case blas.Upper:
  147. return true
  148. case blas.Lower:
  149. return false
  150. default:
  151. panic(badTriangle)
  152. }
  153. }
  154. func uploToTriKind(u blas.Uplo) TriKind {
  155. switch u {
  156. case blas.Upper:
  157. return Upper
  158. case blas.Lower:
  159. return Lower
  160. default:
  161. panic(badTriangle)
  162. }
  163. }
  164. // asSymBlas returns the receiver restructured as a blas64.Symmetric with the
  165. // same backing memory. Panics if the receiver is unit.
  166. // This returns a blas64.Symmetric and not a *SymDense because SymDense can only
  167. // be upper triangular.
  168. func (t *TriDense) asSymBlas() blas64.Symmetric {
  169. if t.mat.Diag == blas.Unit {
  170. panic("mat: cannot convert unit TriDense into blas64.Symmetric")
  171. }
  172. return blas64.Symmetric{
  173. N: t.mat.N,
  174. Stride: t.mat.Stride,
  175. Data: t.mat.Data,
  176. Uplo: t.mat.Uplo,
  177. }
  178. }
  179. // T performs an implicit transpose by returning the receiver inside a Transpose.
  180. func (t *TriDense) T() Matrix {
  181. return Transpose{t}
  182. }
  183. // TTri performs an implicit transpose by returning the receiver inside a TransposeTri.
  184. func (t *TriDense) TTri() Triangular {
  185. return TransposeTri{t}
  186. }
  187. func (t *TriDense) RawTriangular() blas64.Triangular {
  188. return t.mat
  189. }
  190. // SetRawTriangular sets the underlying blas64.Triangular used by the receiver.
  191. // Changes to elements in the receiver following the call will be reflected
  192. // in the input.
  193. //
  194. // The supplied Triangular must not use blas.Unit storage format.
  195. func (t *TriDense) SetRawTriangular(mat blas64.Triangular) {
  196. if mat.Diag == blas.Unit {
  197. panic("mat: cannot set TriDense with Unit storage format")
  198. }
  199. t.cap = mat.N
  200. t.mat = mat
  201. }
  202. // Reset empties the matrix so that it can be reused as the
  203. // receiver of a dimensionally restricted operation.
  204. //
  205. // Reset should not be used when the matrix shares backing data.
  206. // See the Reseter interface for more information.
  207. func (t *TriDense) Reset() {
  208. // N and Stride must be zeroed in unison.
  209. t.mat.N, t.mat.Stride = 0, 0
  210. // Defensively zero Uplo to ensure
  211. // it is set correctly later.
  212. t.mat.Uplo = 0
  213. t.mat.Data = t.mat.Data[:0]
  214. }
  215. // Zero sets all of the matrix elements to zero.
  216. func (t *TriDense) Zero() {
  217. if t.isUpper() {
  218. for i := 0; i < t.mat.N; i++ {
  219. zero(t.mat.Data[i*t.mat.Stride+i : i*t.mat.Stride+t.mat.N])
  220. }
  221. return
  222. }
  223. for i := 0; i < t.mat.N; i++ {
  224. zero(t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+i+1])
  225. }
  226. }
  227. // IsEmpty returns whether the receiver is empty. Empty matrices can be the
  228. // receiver for size-restricted operations. The receiver can be emptied using
  229. // Reset.
  230. func (t *TriDense) IsEmpty() bool {
  231. // It must be the case that t.Dims() returns
  232. // zeros in this case. See comment in Reset().
  233. return t.mat.Stride == 0
  234. }
  235. // untranspose untransposes a matrix if applicable. If a is an Untransposer, then
  236. // untranspose returns the underlying matrix and true. If it is not, then it returns
  237. // the input matrix and false.
  238. func untransposeTri(a Triangular) (Triangular, bool) {
  239. if ut, ok := a.(UntransposeTrier); ok {
  240. return ut.UntransposeTri(), true
  241. }
  242. return a, false
  243. }
  244. // ReuseAsTri changes the receiver if it IsEmpty() to be of size n×n.
  245. //
  246. // ReuseAsTri re-uses the backing data slice if it has sufficient capacity,
  247. // otherwise a new slice is allocated. The backing data is zero on return.
  248. //
  249. // ReuseAsTri panics if the receiver is not empty, and panics if
  250. // the input size is less than one. To empty the receiver for re-use,
  251. // Reset should be used.
  252. func (t *TriDense) ReuseAsTri(n int, kind TriKind) {
  253. if n <= 0 {
  254. if n == 0 {
  255. panic(ErrZeroLength)
  256. }
  257. panic(ErrNegativeDimension)
  258. }
  259. if !t.IsEmpty() {
  260. panic(ErrReuseNonEmpty)
  261. }
  262. t.reuseAsZeroed(n, kind)
  263. }
  264. // reuseAsNonZeroed resizes a zero receiver to an n×n triangular matrix with the given
  265. // orientation. If the receiver is non-zero, reuseAsNonZeroed checks that the receiver
  266. // is the correct size and orientation.
  267. func (t *TriDense) reuseAsNonZeroed(n int, kind TriKind) {
  268. // reuseAsNonZeroed must be kept in sync with reuseAsZeroed.
  269. if n == 0 {
  270. panic(ErrZeroLength)
  271. }
  272. ul := blas.Lower
  273. if kind == Upper {
  274. ul = blas.Upper
  275. }
  276. if t.mat.N > t.cap {
  277. panic(badTriCap)
  278. }
  279. if t.IsEmpty() {
  280. t.mat = blas64.Triangular{
  281. N: n,
  282. Stride: n,
  283. Diag: blas.NonUnit,
  284. Data: use(t.mat.Data, n*n),
  285. Uplo: ul,
  286. }
  287. t.cap = n
  288. return
  289. }
  290. if t.mat.N != n {
  291. panic(ErrShape)
  292. }
  293. if t.mat.Uplo != ul {
  294. panic(ErrTriangle)
  295. }
  296. }
  297. // reuseAsZeroed resizes a zero receiver to an n×n triangular matrix with the given
  298. // orientation. If the receiver is non-zero, reuseAsZeroed checks that the receiver
  299. // is the correct size and orientation. It then zeros out the matrix data.
  300. func (t *TriDense) reuseAsZeroed(n int, kind TriKind) {
  301. // reuseAsZeroed must be kept in sync with reuseAsNonZeroed.
  302. if n == 0 {
  303. panic(ErrZeroLength)
  304. }
  305. ul := blas.Lower
  306. if kind == Upper {
  307. ul = blas.Upper
  308. }
  309. if t.mat.N > t.cap {
  310. panic(badTriCap)
  311. }
  312. if t.IsEmpty() {
  313. t.mat = blas64.Triangular{
  314. N: n,
  315. Stride: n,
  316. Diag: blas.NonUnit,
  317. Data: useZeroed(t.mat.Data, n*n),
  318. Uplo: ul,
  319. }
  320. t.cap = n
  321. return
  322. }
  323. if t.mat.N != n {
  324. panic(ErrShape)
  325. }
  326. if t.mat.Uplo != ul {
  327. panic(ErrTriangle)
  328. }
  329. t.Zero()
  330. }
  331. // isolatedWorkspace returns a new TriDense matrix w with the size of a and
  332. // returns a callback to defer which performs cleanup at the return of the call.
  333. // This should be used when a method receiver is the same pointer as an input argument.
  334. func (t *TriDense) isolatedWorkspace(a Triangular) (w *TriDense, restore func()) {
  335. n, kind := a.Triangle()
  336. if n == 0 {
  337. panic(ErrZeroLength)
  338. }
  339. w = getWorkspaceTri(n, kind, false)
  340. return w, func() {
  341. t.Copy(w)
  342. putWorkspaceTri(w)
  343. }
  344. }
  345. // DiagView returns the diagonal as a matrix backed by the original data.
  346. func (t *TriDense) DiagView() Diagonal {
  347. if t.mat.Diag == blas.Unit {
  348. panic("mat: cannot take view of Unit diagonal")
  349. }
  350. n := t.mat.N
  351. return &DiagDense{
  352. mat: blas64.Vector{
  353. N: n,
  354. Inc: t.mat.Stride + 1,
  355. Data: t.mat.Data[:(n-1)*t.mat.Stride+n],
  356. },
  357. }
  358. }
  359. // Copy makes a copy of elements of a into the receiver. It is similar to the
  360. // built-in copy; it copies as much as the overlap between the two matrices and
  361. // returns the number of rows and columns it copied. Only elements within the
  362. // receiver's non-zero triangle are set.
  363. //
  364. // See the Copier interface for more information.
  365. func (t *TriDense) Copy(a Matrix) (r, c int) {
  366. r, c = a.Dims()
  367. r = min(r, t.mat.N)
  368. c = min(c, t.mat.N)
  369. if r == 0 || c == 0 {
  370. return 0, 0
  371. }
  372. switch a := a.(type) {
  373. case RawMatrixer:
  374. amat := a.RawMatrix()
  375. if t.isUpper() {
  376. for i := 0; i < r; i++ {
  377. copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
  378. }
  379. } else {
  380. for i := 0; i < r; i++ {
  381. copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
  382. }
  383. }
  384. case RawTriangular:
  385. amat := a.RawTriangular()
  386. aIsUpper := isUpperUplo(amat.Uplo)
  387. tIsUpper := t.isUpper()
  388. switch {
  389. case tIsUpper && aIsUpper:
  390. for i := 0; i < r; i++ {
  391. copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
  392. }
  393. case !tIsUpper && !aIsUpper:
  394. for i := 0; i < r; i++ {
  395. copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
  396. }
  397. default:
  398. for i := 0; i < r; i++ {
  399. t.set(i, i, amat.Data[i*amat.Stride+i])
  400. }
  401. }
  402. default:
  403. isUpper := t.isUpper()
  404. for i := 0; i < r; i++ {
  405. if isUpper {
  406. for j := i; j < c; j++ {
  407. t.set(i, j, a.At(i, j))
  408. }
  409. } else {
  410. for j := 0; j <= i; j++ {
  411. t.set(i, j, a.At(i, j))
  412. }
  413. }
  414. }
  415. }
  416. return r, c
  417. }
  418. // InverseTri computes the inverse of the triangular matrix a, storing the result
  419. // into the receiver. If a is ill-conditioned, a Condition error will be returned.
  420. // Note that matrix inversion is numerically unstable, and should generally be
  421. // avoided where possible, for example by using the Solve routines.
  422. func (t *TriDense) InverseTri(a Triangular) error {
  423. t.checkOverlapMatrix(a)
  424. n, _ := a.Triangle()
  425. t.reuseAsNonZeroed(a.Triangle())
  426. t.Copy(a)
  427. work := getFloats(3*n, false)
  428. iwork := getInts(n, false)
  429. cond := lapack64.Trcon(CondNorm, t.mat, work, iwork)
  430. putFloats(work)
  431. putInts(iwork)
  432. if math.IsInf(cond, 1) {
  433. return Condition(cond)
  434. }
  435. ok := lapack64.Trtri(t.mat)
  436. if !ok {
  437. return Condition(math.Inf(1))
  438. }
  439. if cond > ConditionTolerance {
  440. return Condition(cond)
  441. }
  442. return nil
  443. }
  444. // MulTri takes the product of triangular matrices a and b and places the result
  445. // in the receiver. The size of a and b must match, and they both must have the
  446. // same TriKind, or Mul will panic.
  447. func (t *TriDense) MulTri(a, b Triangular) {
  448. n, kind := a.Triangle()
  449. nb, kindb := b.Triangle()
  450. if n != nb {
  451. panic(ErrShape)
  452. }
  453. if kind != kindb {
  454. panic(ErrTriangle)
  455. }
  456. aU, _ := untransposeTri(a)
  457. bU, _ := untransposeTri(b)
  458. t.checkOverlapMatrix(bU)
  459. t.checkOverlapMatrix(aU)
  460. t.reuseAsNonZeroed(n, kind)
  461. var restore func()
  462. if t == aU {
  463. t, restore = t.isolatedWorkspace(aU)
  464. defer restore()
  465. } else if t == bU {
  466. t, restore = t.isolatedWorkspace(bU)
  467. defer restore()
  468. }
  469. // Inspect types here, helps keep the loops later clean(er).
  470. _, aDiag := aU.(Diagonal)
  471. _, bDiag := bU.(Diagonal)
  472. // If they are both diagonal only need 1 loop.
  473. // All diagonal matrices are Upper.
  474. // TODO: Add fast paths for DiagDense.
  475. if aDiag && bDiag {
  476. t.Zero()
  477. for i := 0; i < n; i++ {
  478. t.SetTri(i, i, a.At(i, i)*b.At(i, i))
  479. }
  480. return
  481. }
  482. // Now we know at least one matrix is non-diagonal.
  483. // And all diagonal matrices are all Upper.
  484. // The both-diagonal case is handled above.
  485. // TODO: Add fast paths for Dense variants.
  486. if kind == Upper {
  487. for i := 0; i < n; i++ {
  488. for j := i; j < n; j++ {
  489. switch {
  490. case aDiag:
  491. t.SetTri(i, j, a.At(i, i)*b.At(i, j))
  492. case bDiag:
  493. t.SetTri(i, j, a.At(i, j)*b.At(j, j))
  494. default:
  495. var v float64
  496. for k := i; k <= j; k++ {
  497. v += a.At(i, k) * b.At(k, j)
  498. }
  499. t.SetTri(i, j, v)
  500. }
  501. }
  502. }
  503. return
  504. }
  505. for i := 0; i < n; i++ {
  506. for j := 0; j <= i; j++ {
  507. var v float64
  508. for k := j; k <= i; k++ {
  509. v += a.At(i, k) * b.At(k, j)
  510. }
  511. t.SetTri(i, j, v)
  512. }
  513. }
  514. }
  515. // ScaleTri multiplies the elements of a by f, placing the result in the receiver.
  516. // If the receiver is non-zero, the size and kind of the receiver must match
  517. // the input, or ScaleTri will panic.
  518. func (t *TriDense) ScaleTri(f float64, a Triangular) {
  519. n, kind := a.Triangle()
  520. t.reuseAsNonZeroed(n, kind)
  521. // TODO(btracey): Improve the set of fast-paths.
  522. switch a := a.(type) {
  523. case RawTriangular:
  524. amat := a.RawTriangular()
  525. if t != a {
  526. t.checkOverlap(generalFromTriangular(amat))
  527. }
  528. if kind == Upper {
  529. for i := 0; i < n; i++ {
  530. ts := t.mat.Data[i*t.mat.Stride+i : i*t.mat.Stride+n]
  531. as := amat.Data[i*amat.Stride+i : i*amat.Stride+n]
  532. for i, v := range as {
  533. ts[i] = v * f
  534. }
  535. }
  536. return
  537. }
  538. for i := 0; i < n; i++ {
  539. ts := t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+i+1]
  540. as := amat.Data[i*amat.Stride : i*amat.Stride+i+1]
  541. for i, v := range as {
  542. ts[i] = v * f
  543. }
  544. }
  545. return
  546. default:
  547. t.checkOverlapMatrix(a)
  548. isUpper := kind == Upper
  549. for i := 0; i < n; i++ {
  550. if isUpper {
  551. for j := i; j < n; j++ {
  552. t.set(i, j, f*a.At(i, j))
  553. }
  554. } else {
  555. for j := 0; j <= i; j++ {
  556. t.set(i, j, f*a.At(i, j))
  557. }
  558. }
  559. }
  560. }
  561. }
  562. // Trace returns the trace of the matrix.
  563. func (t *TriDense) Trace() float64 {
  564. // TODO(btracey): could use internal asm sum routine.
  565. var v float64
  566. for i := 0; i < t.mat.N; i++ {
  567. v += t.mat.Data[i*t.mat.Stride+i]
  568. }
  569. return v
  570. }
  571. // copySymIntoTriangle copies a symmetric matrix into a TriDense
  572. func copySymIntoTriangle(t *TriDense, s Symmetric) {
  573. n, upper := t.Triangle()
  574. ns := s.Symmetric()
  575. if n != ns {
  576. panic("mat: triangle size mismatch")
  577. }
  578. ts := t.mat.Stride
  579. if rs, ok := s.(RawSymmetricer); ok {
  580. sd := rs.RawSymmetric()
  581. ss := sd.Stride
  582. if upper {
  583. if sd.Uplo == blas.Upper {
  584. for i := 0; i < n; i++ {
  585. copy(t.mat.Data[i*ts+i:i*ts+n], sd.Data[i*ss+i:i*ss+n])
  586. }
  587. return
  588. }
  589. for i := 0; i < n; i++ {
  590. for j := i; j < n; j++ {
  591. t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
  592. }
  593. }
  594. return
  595. }
  596. if sd.Uplo == blas.Upper {
  597. for i := 0; i < n; i++ {
  598. for j := 0; j <= i; j++ {
  599. t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
  600. }
  601. }
  602. return
  603. }
  604. for i := 0; i < n; i++ {
  605. copy(t.mat.Data[i*ts:i*ts+i+1], sd.Data[i*ss:i*ss+i+1])
  606. }
  607. return
  608. }
  609. if upper {
  610. for i := 0; i < n; i++ {
  611. for j := i; j < n; j++ {
  612. t.mat.Data[i*ts+j] = s.At(i, j)
  613. }
  614. }
  615. return
  616. }
  617. for i := 0; i < n; i++ {
  618. for j := 0; j <= i; j++ {
  619. t.mat.Data[i*ts+j] = s.At(i, j)
  620. }
  621. }
  622. }
  623. // DoNonZero calls the function fn for each of the non-zero elements of t. The function fn
  624. // takes a row/column index and the element value of t at (i, j).
  625. func (t *TriDense) DoNonZero(fn func(i, j int, v float64)) {
  626. if t.isUpper() {
  627. for i := 0; i < t.mat.N; i++ {
  628. for j := i; j < t.mat.N; j++ {
  629. v := t.at(i, j)
  630. if v != 0 {
  631. fn(i, j, v)
  632. }
  633. }
  634. }
  635. return
  636. }
  637. for i := 0; i < t.mat.N; i++ {
  638. for j := 0; j <= i; j++ {
  639. v := t.at(i, j)
  640. if v != 0 {
  641. fn(i, j, v)
  642. }
  643. }
  644. }
  645. }
  646. // DoRowNonZero calls the function fn for each of the non-zero elements of row i of t. The function fn
  647. // takes a row/column index and the element value of t at (i, j).
  648. func (t *TriDense) DoRowNonZero(i int, fn func(i, j int, v float64)) {
  649. if i < 0 || t.mat.N <= i {
  650. panic(ErrRowAccess)
  651. }
  652. if t.isUpper() {
  653. for j := i; j < t.mat.N; j++ {
  654. v := t.at(i, j)
  655. if v != 0 {
  656. fn(i, j, v)
  657. }
  658. }
  659. return
  660. }
  661. for j := 0; j <= i; j++ {
  662. v := t.at(i, j)
  663. if v != 0 {
  664. fn(i, j, v)
  665. }
  666. }
  667. }
  668. // DoColNonZero calls the function fn for each of the non-zero elements of column j of t. The function fn
  669. // takes a row/column index and the element value of t at (i, j).
  670. func (t *TriDense) DoColNonZero(j int, fn func(i, j int, v float64)) {
  671. if j < 0 || t.mat.N <= j {
  672. panic(ErrColAccess)
  673. }
  674. if t.isUpper() {
  675. for i := 0; i <= j; i++ {
  676. v := t.at(i, j)
  677. if v != 0 {
  678. fn(i, j, v)
  679. }
  680. }
  681. return
  682. }
  683. for i := j; i < t.mat.N; i++ {
  684. v := t.at(i, j)
  685. if v != 0 {
  686. fn(i, j, v)
  687. }
  688. }
  689. }