triangular.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  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. // asSymBlas returns the receiver restructured as a blas64.Symmetric with the
  155. // same backing memory. Panics if the receiver is unit.
  156. // This returns a blas64.Symmetric and not a *SymDense because SymDense can only
  157. // be upper triangular.
  158. func (t *TriDense) asSymBlas() blas64.Symmetric {
  159. if t.mat.Diag == blas.Unit {
  160. panic("mat: cannot convert unit TriDense into blas64.Symmetric")
  161. }
  162. return blas64.Symmetric{
  163. N: t.mat.N,
  164. Stride: t.mat.Stride,
  165. Data: t.mat.Data,
  166. Uplo: t.mat.Uplo,
  167. }
  168. }
  169. // T performs an implicit transpose by returning the receiver inside a Transpose.
  170. func (t *TriDense) T() Matrix {
  171. return Transpose{t}
  172. }
  173. // TTri performs an implicit transpose by returning the receiver inside a TransposeTri.
  174. func (t *TriDense) TTri() Triangular {
  175. return TransposeTri{t}
  176. }
  177. func (t *TriDense) RawTriangular() blas64.Triangular {
  178. return t.mat
  179. }
  180. // SetRawTriangular sets the underlying blas64.Triangular used by the receiver.
  181. // Changes to elements in the receiver following the call will be reflected
  182. // in the input.
  183. //
  184. // The supplied Triangular must not use blas.Unit storage format.
  185. func (t *TriDense) SetRawTriangular(mat blas64.Triangular) {
  186. if mat.Diag == blas.Unit {
  187. panic("mat: cannot set TriDense with Unit storage format")
  188. }
  189. t.cap = mat.N
  190. t.mat = mat
  191. }
  192. // Reset empties the matrix so that it can be reused as the
  193. // receiver of a dimensionally restricted operation.
  194. //
  195. // Reset should not be used when the matrix shares backing data.
  196. // See the Reseter interface for more information.
  197. func (t *TriDense) Reset() {
  198. // N and Stride must be zeroed in unison.
  199. t.mat.N, t.mat.Stride = 0, 0
  200. // Defensively zero Uplo to ensure
  201. // it is set correctly later.
  202. t.mat.Uplo = 0
  203. t.mat.Data = t.mat.Data[:0]
  204. }
  205. // Zero sets all of the matrix elements to zero.
  206. func (t *TriDense) Zero() {
  207. if t.isUpper() {
  208. for i := 0; i < t.mat.N; i++ {
  209. zero(t.mat.Data[i*t.mat.Stride+i : i*t.mat.Stride+t.mat.N])
  210. }
  211. return
  212. }
  213. for i := 0; i < t.mat.N; i++ {
  214. zero(t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+i+1])
  215. }
  216. }
  217. // IsEmpty returns whether the receiver is empty. Empty matrices can be the
  218. // receiver for size-restricted operations. The receiver can be emptied using
  219. // Reset.
  220. func (t *TriDense) IsEmpty() bool {
  221. // It must be the case that t.Dims() returns
  222. // zeros in this case. See comment in Reset().
  223. return t.mat.Stride == 0
  224. }
  225. // untranspose untransposes a matrix if applicable. If a is an Untransposer, then
  226. // untranspose returns the underlying matrix and true. If it is not, then it returns
  227. // the input matrix and false.
  228. func untransposeTri(a Triangular) (Triangular, bool) {
  229. if ut, ok := a.(UntransposeTrier); ok {
  230. return ut.UntransposeTri(), true
  231. }
  232. return a, false
  233. }
  234. // ReuseAsTri changes the receiver if it IsEmpty() to be of size n×n.
  235. //
  236. // ReuseAsTri re-uses the backing data slice if it has sufficient capacity,
  237. // otherwise a new slice is allocated. The backing data is zero on return.
  238. //
  239. // ReuseAsTri panics if the receiver is not empty, and panics if
  240. // the input size is less than one. To empty the receiver for re-use,
  241. // Reset should be used.
  242. func (t *TriDense) ReuseAsTri(n int, kind TriKind) {
  243. if n <= 0 {
  244. if n == 0 {
  245. panic(ErrZeroLength)
  246. }
  247. panic(ErrNegativeDimension)
  248. }
  249. if !t.IsEmpty() {
  250. panic(ErrReuseNonEmpty)
  251. }
  252. t.reuseAsZeroed(n, kind)
  253. }
  254. // reuseAsNonZeroed resizes a zero receiver to an n×n triangular matrix with the given
  255. // orientation. If the receiver is non-zero, reuseAsNonZeroed checks that the receiver
  256. // is the correct size and orientation.
  257. func (t *TriDense) reuseAsNonZeroed(n int, kind TriKind) {
  258. // reuseAsNonZeroed must be kept in sync with reuseAsZeroed.
  259. if n == 0 {
  260. panic(ErrZeroLength)
  261. }
  262. ul := blas.Lower
  263. if kind == Upper {
  264. ul = blas.Upper
  265. }
  266. if t.mat.N > t.cap {
  267. panic(badTriCap)
  268. }
  269. if t.IsEmpty() {
  270. t.mat = blas64.Triangular{
  271. N: n,
  272. Stride: n,
  273. Diag: blas.NonUnit,
  274. Data: use(t.mat.Data, n*n),
  275. Uplo: ul,
  276. }
  277. t.cap = n
  278. return
  279. }
  280. if t.mat.N != n {
  281. panic(ErrShape)
  282. }
  283. if t.mat.Uplo != ul {
  284. panic(ErrTriangle)
  285. }
  286. }
  287. // reuseAsZeroed resizes a zero receiver to an n×n triangular matrix with the given
  288. // orientation. If the receiver is non-zero, reuseAsZeroed checks that the receiver
  289. // is the correct size and orientation. It then zeros out the matrix data.
  290. func (t *TriDense) reuseAsZeroed(n int, kind TriKind) {
  291. // reuseAsZeroed must be kept in sync with reuseAsNonZeroed.
  292. if n == 0 {
  293. panic(ErrZeroLength)
  294. }
  295. ul := blas.Lower
  296. if kind == Upper {
  297. ul = blas.Upper
  298. }
  299. if t.mat.N > t.cap {
  300. panic(badTriCap)
  301. }
  302. if t.IsEmpty() {
  303. t.mat = blas64.Triangular{
  304. N: n,
  305. Stride: n,
  306. Diag: blas.NonUnit,
  307. Data: useZeroed(t.mat.Data, n*n),
  308. Uplo: ul,
  309. }
  310. t.cap = n
  311. return
  312. }
  313. if t.mat.N != n {
  314. panic(ErrShape)
  315. }
  316. if t.mat.Uplo != ul {
  317. panic(ErrTriangle)
  318. }
  319. t.Zero()
  320. }
  321. // isolatedWorkspace returns a new TriDense matrix w with the size of a and
  322. // returns a callback to defer which performs cleanup at the return of the call.
  323. // This should be used when a method receiver is the same pointer as an input argument.
  324. func (t *TriDense) isolatedWorkspace(a Triangular) (w *TriDense, restore func()) {
  325. n, kind := a.Triangle()
  326. if n == 0 {
  327. panic(ErrZeroLength)
  328. }
  329. w = getWorkspaceTri(n, kind, false)
  330. return w, func() {
  331. t.Copy(w)
  332. putWorkspaceTri(w)
  333. }
  334. }
  335. // DiagView returns the diagonal as a matrix backed by the original data.
  336. func (t *TriDense) DiagView() Diagonal {
  337. if t.mat.Diag == blas.Unit {
  338. panic("mat: cannot take view of Unit diagonal")
  339. }
  340. n := t.mat.N
  341. return &DiagDense{
  342. mat: blas64.Vector{
  343. N: n,
  344. Inc: t.mat.Stride + 1,
  345. Data: t.mat.Data[:(n-1)*t.mat.Stride+n],
  346. },
  347. }
  348. }
  349. // Copy makes a copy of elements of a into the receiver. It is similar to the
  350. // built-in copy; it copies as much as the overlap between the two matrices and
  351. // returns the number of rows and columns it copied. Only elements within the
  352. // receiver's non-zero triangle are set.
  353. //
  354. // See the Copier interface for more information.
  355. func (t *TriDense) Copy(a Matrix) (r, c int) {
  356. r, c = a.Dims()
  357. r = min(r, t.mat.N)
  358. c = min(c, t.mat.N)
  359. if r == 0 || c == 0 {
  360. return 0, 0
  361. }
  362. switch a := a.(type) {
  363. case RawMatrixer:
  364. amat := a.RawMatrix()
  365. if t.isUpper() {
  366. for i := 0; i < r; i++ {
  367. copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
  368. }
  369. } else {
  370. for i := 0; i < r; i++ {
  371. copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
  372. }
  373. }
  374. case RawTriangular:
  375. amat := a.RawTriangular()
  376. aIsUpper := isUpperUplo(amat.Uplo)
  377. tIsUpper := t.isUpper()
  378. switch {
  379. case tIsUpper && aIsUpper:
  380. for i := 0; i < r; i++ {
  381. copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
  382. }
  383. case !tIsUpper && !aIsUpper:
  384. for i := 0; i < r; i++ {
  385. copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
  386. }
  387. default:
  388. for i := 0; i < r; i++ {
  389. t.set(i, i, amat.Data[i*amat.Stride+i])
  390. }
  391. }
  392. default:
  393. isUpper := t.isUpper()
  394. for i := 0; i < r; i++ {
  395. if isUpper {
  396. for j := i; j < c; j++ {
  397. t.set(i, j, a.At(i, j))
  398. }
  399. } else {
  400. for j := 0; j <= i; j++ {
  401. t.set(i, j, a.At(i, j))
  402. }
  403. }
  404. }
  405. }
  406. return r, c
  407. }
  408. // InverseTri computes the inverse of the triangular matrix a, storing the result
  409. // into the receiver. If a is ill-conditioned, a Condition error will be returned.
  410. // Note that matrix inversion is numerically unstable, and should generally be
  411. // avoided where possible, for example by using the Solve routines.
  412. func (t *TriDense) InverseTri(a Triangular) error {
  413. t.checkOverlapMatrix(a)
  414. n, _ := a.Triangle()
  415. t.reuseAsNonZeroed(a.Triangle())
  416. t.Copy(a)
  417. work := getFloats(3*n, false)
  418. iwork := getInts(n, false)
  419. cond := lapack64.Trcon(CondNorm, t.mat, work, iwork)
  420. putFloats(work)
  421. putInts(iwork)
  422. if math.IsInf(cond, 1) {
  423. return Condition(cond)
  424. }
  425. ok := lapack64.Trtri(t.mat)
  426. if !ok {
  427. return Condition(math.Inf(1))
  428. }
  429. if cond > ConditionTolerance {
  430. return Condition(cond)
  431. }
  432. return nil
  433. }
  434. // MulTri takes the product of triangular matrices a and b and places the result
  435. // in the receiver. The size of a and b must match, and they both must have the
  436. // same TriKind, or Mul will panic.
  437. func (t *TriDense) MulTri(a, b Triangular) {
  438. n, kind := a.Triangle()
  439. nb, kindb := b.Triangle()
  440. if n != nb {
  441. panic(ErrShape)
  442. }
  443. if kind != kindb {
  444. panic(ErrTriangle)
  445. }
  446. aU, _ := untransposeTri(a)
  447. bU, _ := untransposeTri(b)
  448. t.checkOverlapMatrix(bU)
  449. t.checkOverlapMatrix(aU)
  450. t.reuseAsNonZeroed(n, kind)
  451. var restore func()
  452. if t == aU {
  453. t, restore = t.isolatedWorkspace(aU)
  454. defer restore()
  455. } else if t == bU {
  456. t, restore = t.isolatedWorkspace(bU)
  457. defer restore()
  458. }
  459. // Inspect types here, helps keep the loops later clean(er).
  460. _, aDiag := aU.(Diagonal)
  461. _, bDiag := bU.(Diagonal)
  462. // If they are both diagonal only need 1 loop.
  463. // All diagonal matrices are Upper.
  464. // TODO: Add fast paths for DiagDense.
  465. if aDiag && bDiag {
  466. t.Zero()
  467. for i := 0; i < n; i++ {
  468. t.SetTri(i, i, a.At(i, i)*b.At(i, i))
  469. }
  470. return
  471. }
  472. // Now we know at least one matrix is non-diagonal.
  473. // And all diagonal matrices are all Upper.
  474. // The both-diagonal case is handled above.
  475. // TODO: Add fast paths for Dense variants.
  476. if kind == Upper {
  477. for i := 0; i < n; i++ {
  478. for j := i; j < n; j++ {
  479. switch {
  480. case aDiag:
  481. t.SetTri(i, j, a.At(i, i)*b.At(i, j))
  482. case bDiag:
  483. t.SetTri(i, j, a.At(i, j)*b.At(j, j))
  484. default:
  485. var v float64
  486. for k := i; k <= j; k++ {
  487. v += a.At(i, k) * b.At(k, j)
  488. }
  489. t.SetTri(i, j, v)
  490. }
  491. }
  492. }
  493. return
  494. }
  495. for i := 0; i < n; i++ {
  496. for j := 0; j <= i; j++ {
  497. var v float64
  498. for k := j; k <= i; k++ {
  499. v += a.At(i, k) * b.At(k, j)
  500. }
  501. t.SetTri(i, j, v)
  502. }
  503. }
  504. }
  505. // ScaleTri multiplies the elements of a by f, placing the result in the receiver.
  506. // If the receiver is non-zero, the size and kind of the receiver must match
  507. // the input, or ScaleTri will panic.
  508. func (t *TriDense) ScaleTri(f float64, a Triangular) {
  509. n, kind := a.Triangle()
  510. t.reuseAsNonZeroed(n, kind)
  511. // TODO(btracey): Improve the set of fast-paths.
  512. switch a := a.(type) {
  513. case RawTriangular:
  514. amat := a.RawTriangular()
  515. if t != a {
  516. t.checkOverlap(generalFromTriangular(amat))
  517. }
  518. if kind == Upper {
  519. for i := 0; i < n; i++ {
  520. ts := t.mat.Data[i*t.mat.Stride+i : i*t.mat.Stride+n]
  521. as := amat.Data[i*amat.Stride+i : i*amat.Stride+n]
  522. for i, v := range as {
  523. ts[i] = v * f
  524. }
  525. }
  526. return
  527. }
  528. for i := 0; i < n; i++ {
  529. ts := t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+i+1]
  530. as := amat.Data[i*amat.Stride : i*amat.Stride+i+1]
  531. for i, v := range as {
  532. ts[i] = v * f
  533. }
  534. }
  535. return
  536. default:
  537. t.checkOverlapMatrix(a)
  538. isUpper := kind == Upper
  539. for i := 0; i < n; i++ {
  540. if isUpper {
  541. for j := i; j < n; j++ {
  542. t.set(i, j, f*a.At(i, j))
  543. }
  544. } else {
  545. for j := 0; j <= i; j++ {
  546. t.set(i, j, f*a.At(i, j))
  547. }
  548. }
  549. }
  550. }
  551. }
  552. // SliceTri returns a new Triangular that shares backing data with the receiver.
  553. // The returned matrix starts at {i,i} of the receiver and extends k-i rows and
  554. // columns. The final row and column in the resulting matrix is k-1.
  555. // SliceTri panics with ErrIndexOutOfRange if the slice is outside the capacity
  556. // of the receiver.
  557. func (t *TriDense) SliceTri(i, k int) Triangular {
  558. return t.sliceTri(i, k)
  559. }
  560. func (t *TriDense) sliceTri(i, k int) *TriDense {
  561. if i < 0 || t.cap < i || k < i || t.cap < k {
  562. panic(ErrIndexOutOfRange)
  563. }
  564. v := *t
  565. v.mat.Data = t.mat.Data[i*t.mat.Stride+i : (k-1)*t.mat.Stride+k]
  566. v.mat.N = k - i
  567. v.cap = t.cap - i
  568. return &v
  569. }
  570. // Trace returns the trace of the matrix.
  571. func (t *TriDense) Trace() float64 {
  572. // TODO(btracey): could use internal asm sum routine.
  573. var v float64
  574. for i := 0; i < t.mat.N; i++ {
  575. v += t.mat.Data[i*t.mat.Stride+i]
  576. }
  577. return v
  578. }
  579. // copySymIntoTriangle copies a symmetric matrix into a TriDense
  580. func copySymIntoTriangle(t *TriDense, s Symmetric) {
  581. n, upper := t.Triangle()
  582. ns := s.Symmetric()
  583. if n != ns {
  584. panic("mat: triangle size mismatch")
  585. }
  586. ts := t.mat.Stride
  587. if rs, ok := s.(RawSymmetricer); ok {
  588. sd := rs.RawSymmetric()
  589. ss := sd.Stride
  590. if upper {
  591. if sd.Uplo == blas.Upper {
  592. for i := 0; i < n; i++ {
  593. copy(t.mat.Data[i*ts+i:i*ts+n], sd.Data[i*ss+i:i*ss+n])
  594. }
  595. return
  596. }
  597. for i := 0; i < n; i++ {
  598. for j := i; j < n; j++ {
  599. t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
  600. }
  601. }
  602. return
  603. }
  604. if sd.Uplo == blas.Upper {
  605. for i := 0; i < n; i++ {
  606. for j := 0; j <= i; j++ {
  607. t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
  608. }
  609. }
  610. return
  611. }
  612. for i := 0; i < n; i++ {
  613. copy(t.mat.Data[i*ts:i*ts+i+1], sd.Data[i*ss:i*ss+i+1])
  614. }
  615. return
  616. }
  617. if upper {
  618. for i := 0; i < n; i++ {
  619. for j := i; j < n; j++ {
  620. t.mat.Data[i*ts+j] = s.At(i, j)
  621. }
  622. }
  623. return
  624. }
  625. for i := 0; i < n; i++ {
  626. for j := 0; j <= i; j++ {
  627. t.mat.Data[i*ts+j] = s.At(i, j)
  628. }
  629. }
  630. }
  631. // DoNonZero calls the function fn for each of the non-zero elements of t. The function fn
  632. // takes a row/column index and the element value of t at (i, j).
  633. func (t *TriDense) DoNonZero(fn func(i, j int, v float64)) {
  634. if t.isUpper() {
  635. for i := 0; i < t.mat.N; i++ {
  636. for j := i; j < t.mat.N; j++ {
  637. v := t.at(i, j)
  638. if v != 0 {
  639. fn(i, j, v)
  640. }
  641. }
  642. }
  643. return
  644. }
  645. for i := 0; i < t.mat.N; i++ {
  646. for j := 0; j <= i; j++ {
  647. v := t.at(i, j)
  648. if v != 0 {
  649. fn(i, j, v)
  650. }
  651. }
  652. }
  653. }
  654. // DoRowNonZero calls the function fn for each of the non-zero elements of row i of t. The function fn
  655. // takes a row/column index and the element value of t at (i, j).
  656. func (t *TriDense) DoRowNonZero(i int, fn func(i, j int, v float64)) {
  657. if i < 0 || t.mat.N <= i {
  658. panic(ErrRowAccess)
  659. }
  660. if t.isUpper() {
  661. for j := i; j < t.mat.N; j++ {
  662. v := t.at(i, j)
  663. if v != 0 {
  664. fn(i, j, v)
  665. }
  666. }
  667. return
  668. }
  669. for j := 0; j <= i; j++ {
  670. v := t.at(i, j)
  671. if v != 0 {
  672. fn(i, j, v)
  673. }
  674. }
  675. }
  676. // DoColNonZero calls the function fn for each of the non-zero elements of column j of t. The function fn
  677. // takes a row/column index and the element value of t at (i, j).
  678. func (t *TriDense) DoColNonZero(j int, fn func(i, j int, v float64)) {
  679. if j < 0 || t.mat.N <= j {
  680. panic(ErrColAccess)
  681. }
  682. if t.isUpper() {
  683. for i := 0; i <= j; i++ {
  684. v := t.at(i, j)
  685. if v != 0 {
  686. fn(i, j, v)
  687. }
  688. }
  689. return
  690. }
  691. for i := j; i < t.mat.N; i++ {
  692. v := t.at(i, j)
  693. if v != 0 {
  694. fn(i, j, v)
  695. }
  696. }
  697. }