tensor.lisp (21817B)
1 (defpackage :tensor 2 (:use :common-lisp :util :blas :array :exp) 3 (:export :tensor 4 :make-tensor 5 :tensor-indices 6 :tensor-sectors 7 :segment 8 :make-segment 9 :segment-numbers 10 :segment-dimension 11 :subscript 12 :make-subscript 13 :subscript-numbers 14 :subscript-subscript 15 :sector 16 :make-sector 17 :sector-numbers 18 :sector-array 19 :list-+ 20 :list-- 21 :list-zerop 22 :functional-tensor 23 :conjugate-index 24 :tensor-rank 25 :tensor-dimensions 26 :tensor-total-size 27 :tensor-scalar 28 :tensor-normalize 29 :tensor-conjugate 30 :tensor-contract 31 :tensor-permute 32 :tensor-fuse 33 :tensor-decompose 34 :tensor-exponential)) 35 36 (in-package :tensor) 37 38 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 39 40 (defstruct tensor 41 (indices nil :type list) 42 (sectors nil :type list)) 43 44 (defstruct segment 45 (numbers nil :type list) 46 (dimension 0 :type fixnum)) 47 48 (defstruct subscript 49 (numbers nil :type list) 50 (subscript 0 :type fixnum)) 51 52 (defstruct sector 53 (numbers nil :type list) 54 array) 55 56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 57 58 (defun list-+ (&rest args) 59 (apply #'mapcar #'+ args)) 60 61 ;; (defun list-- (&rest args) 62 ;; (apply #'mapcar #'- args)) 63 64 ;; optimized version with a single argument 65 66 (defun list-- (l) 67 (loop for i in l collect (- i))) 68 69 (defun list-zerop (list) 70 (if list 71 (and (zerop (the fixnum (car list))) (list-zerop (cdr list))) 72 t)) 73 74 (defun list-< (a b) 75 (cond 76 ((null a) (not (null b))) 77 ((null b) nil) 78 ((= (the fixnum (car a)) (the fixnum (car b))) (list-< (cdr a) (cdr b))) 79 (t (< (the fixnum (car a)) (the fixnum (car b)))))) 80 81 (defun array-zerop (array) 82 (declare (type (array blas-float) array)) 83 (dotimes (i (array-total-size array) t) 84 (unless (zerop (row-major-aref array i)) (return nil)))) 85 86 (defun sort-index (index) 87 (sort (copy-list index) #'list-< :key #'segment-numbers)) 88 89 (defun remove-zero-sectors (sectors) 90 (mapcan 91 #'(lambda (s) 92 (unless (array-zerop (sector-array s)) 93 (list s))) 94 sectors)) 95 96 (defun tensor-index-sequence (indices) 97 (mapcar 98 #'(lambda (mi) (mapcar #'nth mi indices)) 99 (multi-index-sequence (mapcar #'length indices)))) 100 101 (defun functional-tensor (indices function) 102 (let ((si (mapcar #'sort-index indices))) 103 (make-tensor 104 :indices 105 si 106 :sectors 107 (remove-zero-sectors 108 (mapcan 109 #'(lambda (ts) 110 (let ((mn (mapcar #'segment-numbers ts)) 111 (md (mapcar #'segment-dimension ts))) 112 (when (list-zerop (apply #'list-+ mn)) ; symmetry condition 113 (let ((a (make-blas-array md))) 114 (dolist (mi (multi-index-sequence md) 115 (list (make-sector :numbers mn :array a))) 116 (setf (apply #'aref a mi) 117 (coerce (funcall function 118 (mapcar 119 #'(lambda (n i) 120 (make-subscript 121 :numbers n 122 :subscript i)) 123 mn 124 mi)) 125 'blas-float))))))) 126 (tensor-index-sequence si)))))) 127 128 (defun conjugate-index (index) 129 (reverse 130 (mapcar #'(lambda (s) 131 (make-segment 132 :numbers (list-- (segment-numbers s)) 133 :dimension (segment-dimension s))) 134 index))) 135 136 (defun tensor-rank (tensor) 137 (length (tensor-indices tensor))) 138 139 (defun tensor-dimensions (tensor) 140 (loop 141 for i in (tensor-indices tensor) 142 collect (reduce #'+ i :key #'segment-dimension))) 143 144 (defun tensor-total-size (tensor) 145 (reduce #'+ (tensor-sectors tensor) :key #'(lambda (s) (array-total-size (sector-array s))))) 146 147 (defun tensor-scalar (tensor) 148 (let ((s (tensor-sectors tensor))) 149 (if s 150 (aref (sector-array (first s))) 151 +blas-0+))) 152 153 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 154 155 ;; tensor-normalize 156 157 (defun tensor-norm (tensor) 158 (sqrt 159 (loop 160 for s in (tensor-sectors tensor) 161 sum (expt (array-norm (sector-array s)) 2)))) 162 163 (defun tensor-normalize (tensor) 164 (let ((n (tensor-norm tensor))) 165 (make-tensor 166 :indices 167 (tensor-indices tensor) 168 :sectors 169 (mapcar 170 #'(lambda (s) 171 (make-sector 172 :numbers (sector-numbers s) 173 :array (array-scalar-/ (sector-array s) n))) 174 (tensor-sectors tensor))))) 175 176 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 177 178 ;; tensor-conjugate 179 180 (defun tensor-conjugate (tensor) 181 (make-tensor 182 :indices 183 (mapcar 184 #'(lambda (i) 185 (reverse 186 (mapcar #'(lambda (s) 187 (make-segment 188 :numbers (list-- (segment-numbers s)) 189 :dimension (segment-dimension s))) 190 i))) 191 (tensor-indices tensor)) 192 :sectors 193 (mapcar 194 #'(lambda (s) 195 (make-sector 196 :numbers (mapcar #'list-- (sector-numbers s)) 197 :array (array-conjugate (sector-array s)))) 198 (tensor-sectors tensor)))) 199 200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 201 202 ;; tensor-permute 203 204 (defun tensor-permute (tensor permutation) 205 (make-tensor 206 :indices 207 (list-permute (tensor-indices tensor) permutation) 208 :sectors 209 (mapcar 210 #'(lambda (s) 211 (make-sector 212 :numbers (list-permute (sector-numbers s) permutation) 213 :array (array-permute (sector-array s) permutation))) 214 (tensor-sectors tensor)))) 215 216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 217 218 ;; tensor-contract 219 220 (defun index-match-p (x y) 221 (and (= (length x) (length y)) 222 (loop 223 for i in x 224 for j in (reverse y) 225 unless (and (list-zerop (list-+ (segment-numbers i) 226 (segment-numbers j))) 227 (zerop (- (segment-dimension i) 228 (segment-dimension j)))) 229 return nil 230 finally (return t)))) 231 232 (defun indices-match-p (x y) 233 (and (= (length x) (length y)) 234 (loop 235 for i in x 236 for j in y 237 unless (index-match-p i j) 238 return nil 239 finally (return t)))) 240 241 (defun contraction-hash-table (tensor indices) 242 (let ((h (make-hash-table :test 'equal))) 243 (dolist (x (tensor-sectors tensor) h) 244 (push x 245 (gethash (loop 246 with n = (sector-numbers x) 247 for i in indices 248 collect (nth i n)) 249 h))))) 250 251 (defun sector-contract (sector1 indices1 sector2 indices2) 252 (make-sector 253 :numbers 254 (nconc 255 (loop 256 with n = (sector-numbers sector1) 257 for i below (length n) 258 unless (member i indices1) 259 collect (nth i n)) 260 (loop with n = (sector-numbers sector2) 261 for i below (length n) 262 unless (member i indices2) 263 collect (nth i n))) 264 :array 265 (array-contract (sector-array sector1) 266 indices1 267 (sector-array sector2) 268 indices2))) 269 270 (defun tensor-contract (tensor1 indices1 tensor2 indices2) 271 (if (numberp indices1) 272 (setf indices1 (list indices1))) 273 (if (numberp indices2) 274 (setf indices2 (list indices2))) 275 (unless (indices-match-p (loop 276 with n = (tensor-indices tensor1) 277 for i in indices1 278 collect (nth i n)) 279 (loop 280 with n = (tensor-indices tensor2) 281 for i in indices2 282 collect (nth i n))) 283 (error "Contraction indices do not match.")) 284 (let ((h1 (contraction-hash-table tensor1 indices1)) 285 (h2 (contraction-hash-table tensor2 indices2)) 286 (h (make-hash-table :test 'equal))) 287 (loop 288 for k being the hash-keys in h1 289 using (hash-value v1) 290 do (let ((v2 (gethash (loop for i in k collect (list-- i)) h2))) 291 (when v2 292 (dolist (s1 v1) 293 (dolist (s2 v2) 294 (let* ((s (sector-contract s1 indices1 s2 indices2)) 295 (n (sector-numbers s)) 296 (v (gethash n h))) 297 (if v 298 (array-addf (sector-array v) 299 (sector-array s)) 300 (setf (gethash n h) s)))))))) 301 (make-tensor 302 :indices 303 (nconc 304 (loop 305 with n = (tensor-indices tensor1) 306 for i below (length n) 307 unless (member i indices1) 308 collect (nth i n)) 309 (loop 310 with n = (tensor-indices tensor2) 311 for i below (length n) 312 unless (member i indices2) 313 collect (nth i n))) 314 :sectors 315 (remove-zero-sectors 316 (loop 317 for v being the hash-values of h 318 collect v))))) 319 320 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 321 322 ;; tensor-fuse 323 324 (defstruct joint 325 segments 326 subscript) 327 328 (defun joint-numbers (joint) 329 (mapcar #'segment-numbers (joint-segments joint))) 330 331 (defun joint-number (joint) 332 (apply #'list-+ (joint-numbers joint))) 333 334 (defun joint-dimensions (joint) 335 (mapcar #'segment-dimension (joint-segments joint))) 336 337 (defun joint-dimension (joint) 338 (apply #'* (joint-dimensions joint))) 339 340 (defun fused-index-hash-table (indices type) 341 (let ((md (mapcar #'length indices)) 342 (hi (make-hash-table :test #'equal))) 343 (dolist (mi (multi-index-sequence md)) 344 (let ((f (make-joint :segments (mapcar #'nth mi indices)))) 345 (push f (gethash (joint-number f) hi)))) 346 (loop 347 for k being the hash-keys in hi 348 using (hash-value v) 349 do (let ((l (sort v #'list-< :key #'(lambda (n) (apply #'append (joint-numbers n))))) 350 (hf (make-hash-table :test #'equal))) 351 (loop 352 with s = 0 353 for i in (if (eq type :reverse) (reverse l) l) 354 do 355 (setf (joint-subscript i) s) 356 (setf (gethash (joint-numbers i) hf) i) 357 (incf s (joint-dimension i))) 358 (setf (gethash k hi) hf)) 359 finally (return hi)))) 360 361 (defun fused-index-joints (number fiht) 362 (loop 363 for v being the hash-values in (gethash number fiht) 364 collect v)) 365 366 (defun fused-index-dimension (numbers fiht) 367 (loop 368 for v being the hash-values in (gethash numbers fiht) 369 sum (joint-dimension v))) 370 371 (defun fused-index-subscript (numbers fiht) 372 (joint-subscript (gethash numbers (gethash (apply #'list-+ numbers) fiht)))) 373 374 (defun fused-index (fiht) 375 (sort-index 376 (loop 377 for k being the hash-keys in fiht 378 using (hash-value v) 379 collect 380 (make-segment 381 :numbers 382 k 383 :dimension 384 (loop 385 for w being the hash-values in v 386 sum (joint-dimension w)))))) 387 388 (defun partite-list (list borders) 389 (loop 390 with m 391 with s 392 with b = (pop borders) 393 for i below (length list) 394 for j in list 395 when (and b (= i b)) 396 do 397 (push (nreverse s) m) 398 (setf s nil 399 b (pop borders)) 400 do 401 (push j s) 402 finally 403 (push (nreverse s) m) 404 (return (nreverse m)))) 405 406 (defun array-fuse (array borders) 407 (make-blas-array 408 (mapcar #'(lambda (m) (apply #'* m)) 409 (partite-list (array-dimensions array) borders)) 410 :displaced-to array)) 411 412 ;; (defun array-insert-subarray (array subscripts subarray) 413 ;; (dolist (mi (multi-index-sequence (array-dimensions subarray)) 414 ;; subarray) 415 ;; (setf (apply #'aref array (mapcar #'+ subscripts mi)) 416 ;; (apply #'aref subarray mi)))) 417 418 ;; optimized version 419 420 (defun make-array-insert-subarray-fn (rank) 421 (let ((mi (loop for i below rank collect (gensym))) 422 (md (loop for i below rank collect (gensym))) 423 (ms (loop for i below rank collect (gensym)))) 424 (labels ((nest (&optional (i 0)) 425 (if (eql i rank) 426 `(setf (aref array 427 ,@(loop for j below rank 428 collect `(+ ,(nth j ms) ,(nth j mi)))) 429 (aref subarray ,@mi)) 430 `(dotimes (,(nth i mi) ,(nth i md) 431 ,@(when (eql i 0) '(subarray))) 432 ,(nest (1+ i)))))) 433 `(lambda (array subscripts subarray) 434 (declare (type (array blas-float) array subarray)) 435 (let (,@(loop for i below rank 436 collect `(,(nth i md) (array-dimension subarray ,i))) 437 ,@(loop for i below rank 438 collect `(,(nth i ms) (nth ,i subscripts)))) 439 (declare (type fixnum ,@ms)) 440 ,(nest)))))) 441 442 (let ((cache (make-hash-table))) 443 (defun array-insert-subarray (array subscripts subarray) 444 (let ((l (length subscripts))) 445 (funcall (or (gethash l cache) 446 (setf (gethash l cache) 447 (symbol-function 448 (compile (intern (format nil "ARRAY-INSERT-SUBARRAY-~D" l)) 449 (make-array-insert-subarray-fn l))))) 450 array 451 subscripts 452 subarray)))) 453 454 ;; (defun array-extract-subarray (array subscripts dimensions) 455 ;; (let ((a (make-blas-array dimensions))) 456 ;; (dolist (mi (multi-index-sequence dimensions) a) 457 ;; (setf (apply #'aref a mi) 458 ;; (apply #'aref array (mapcar #'+ subscripts mi)))))) 459 460 ;; optimized version 461 462 (defun make-array-extract-subarray-fn (rank) 463 (let ((mi (loop for i below rank collect (gensym))) 464 (md (loop for i below rank collect (gensym))) 465 (ms (loop for i below rank collect (gensym)))) 466 (labels ((nest (&optional (i 0)) 467 (if (eql i rank) 468 `(setf (aref a ,@mi) 469 (aref array 470 ,@(loop for j below rank 471 collect `(+ ,(nth j ms) ,(nth j mi))))) 472 `(dotimes (,(nth i mi) ,(nth i md) 473 ,@(when (eql i 0) '(a))) 474 ,(nest (1+ i)))))) 475 `(lambda (array subscripts dimensions) 476 (declare (type (array blas-float) array) 477 (type list dimensions)) 478 (let ((a (make-blas-array dimensions)) 479 ,@(loop for i below rank 480 collect `(,(nth i md) (nth ,i dimensions))) 481 ,@(loop for i below rank 482 collect `(,(nth i ms) (nth ,i subscripts)))) 483 (declare (type fixnum ,@md ,@ms)) 484 ,(nest)))))) 485 486 (let ((cache (make-hash-table))) 487 (defun array-extract-subarray (array subscripts dimensions) 488 (let ((l (length subscripts))) 489 (funcall (or (gethash l cache) 490 (setf (gethash l cache) 491 (symbol-function 492 (compile (intern (format nil "ARRAY-EXTRACT-SUBARRAY-~D" l)) 493 (make-array-extract-subarray-fn l))))) 494 array 495 subscripts 496 dimensions)))) 497 498 (defun make-fused-array (numbers fiht) 499 (make-blas-array 500 (mapcar #'(lambda (n h) (fused-index-dimension n h)) numbers fiht) 501 :initial-element +blas-0+)) 502 503 (defun fused-array-subscripts (partition fiht) 504 (mapcar #'(lambda (n h) (fused-index-subscript n h)) partition fiht)) 505 506 (defun tensor-fuse (tensor borders types) 507 (let ((f (mapcar #'fused-index-hash-table 508 (partite-list (tensor-indices tensor) borders) 509 types)) 510 (h (make-hash-table :test 'equal))) 511 (dolist (s (tensor-sectors tensor)) 512 (let* ((p (partite-list (sector-numbers s) borders)) 513 (n (mapcar #'(lambda (l) (apply #'list-+ l)) p)) 514 (v (gethash n h))) 515 ;; create the array if it does not exist 516 (unless v 517 (setf v (make-fused-array n f)) 518 (setf (gethash n h) v)) 519 ;; insert sector array into the fused array 520 (array-insert-subarray v 521 (fused-array-subscripts p f) 522 (array-fuse (sector-array s) borders)))) 523 (make-tensor 524 :indices 525 (mapcar #'fused-index f) 526 :sectors 527 (remove-zero-sectors 528 (loop 529 for k being the hash-keys in h 530 using (hash-value v) 531 collect 532 (make-sector :numbers k :array v)))))) 533 534 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 535 536 ;; tensor-decompose 537 538 (defstruct svd 539 numbers 540 u 541 s 542 v) 543 544 (defun svd-reduce-dimensions (svd maxdim normalization) 545 (let* ((u (svd-u svd)) 546 (s (svd-s svd)) 547 (v (svd-v svd)) 548 (ud (array-dimension u 0)) 549 (sd (min maxdim (length s))) 550 (vd (array-dimension v 1)) 551 (un (make-blas-array (list ud sd))) 552 (vn (make-blas-array (list sd vd))) 553 (sn (map 'vector 554 (if (member normalization '(:none :left :right)) 555 #'identity 556 #'sqrt) 557 (subseq s 0 sd)))) 558 (case normalization 559 (:none 560 (dotimes (i ud) 561 (dotimes (j sd) 562 (setf (aref un i j) (aref u i j)))) 563 (dotimes (i sd) 564 (dotimes (j vd) 565 (setf (aref vn i j) (aref v i j))))) 566 (:left 567 (dotimes (i ud) 568 (dotimes (j sd) 569 (setf (aref un i j) (aref u i j)))) 570 (dotimes (i sd) 571 (dotimes (j vd) 572 (setf (aref vn i j) (* (aref v i j) (aref sn i)))))) 573 (:right 574 (dotimes (i ud) 575 (dotimes (j sd) 576 (setf (aref un i j) (* (aref u i j) (aref sn j))))) 577 (dotimes (i sd) 578 (dotimes (j vd) 579 (setf (aref vn i j) (aref v i j))))) 580 (:mixed 581 (dotimes (i ud) 582 (dotimes (j sd) 583 (setf (aref un i j) (* (aref u i j) (aref sn j))))) 584 (dotimes (i sd) 585 (dotimes (j vd) 586 (setf (aref vn i j) (* (aref v i j) (aref sn i))))))) 587 (make-svd :numbers (svd-numbers svd) :u un :v vn))) 588 589 (defun diagonal-matrix (diagonal maxdim) 590 (let* ((n (min maxdim (length diagonal))) 591 (m (make-blas-array (list n n) :initial-element +blas-0+))) 592 (dotimes (i n m) 593 (setf (aref m i i) (coerce (aref diagonal i) 'blas-float))))) 594 595 (defun array-reshape (array dimensions) 596 (let ((a (make-blas-array dimensions))) 597 (dotimes (i (array-total-size a) a) 598 (setf (row-major-aref a i) (row-major-aref array i))))) 599 600 (defun tensor-decompose (tensor indices maxdim normalization) 601 (if (numberp indices) 602 (setf indices (list indices))) 603 ;; permute if necessary 604 (let ((r (tensor-rank tensor))) 605 (unless (and (eql (indices-position r indices) :left) 606 (apply #'< indices)) 607 (let ((l (loop for i below (length indices) collect i))) 608 (setf tensor (tensor-permute tensor (make-indices-permutation r indices l))) 609 (setf indices l)))) 610 (let* ((b (list (length indices))) 611 (p (partite-list (tensor-indices tensor) b)) 612 (f (mapcar #'fused-index-hash-table p '(:normal :reverse))) 613 (ah (make-hash-table :test #'equal)) 614 (sh (make-hash-table :test #'eq)) 615 sl i1 i2 is1 is2 s1 s2 ss) 616 ;; create fused arrays 617 (loop 618 for s in (tensor-sectors tensor) 619 do 620 (let* ((r (partite-list (sector-numbers s) b)) 621 (n (mapcar #'(lambda (l) (apply #'list-+ l)) r)) 622 (a (gethash n ah))) 623 (unless a 624 (setf a (make-fused-array n f)) 625 (setf (gethash n ah) a)) 626 (array-insert-subarray 627 a 628 (fused-array-subscripts r f) 629 (array-fuse (sector-array s) b)))) 630 ;; decompose arrays 631 (loop 632 for n being the hash-keys in ah 633 using (hash-value a) 634 do 635 (multiple-value-bind (u s v) (array-decompose a 0) 636 (let ((x (make-svd :numbers n :u u :s s :v v))) 637 (loop 638 for i across s 639 unless (essentially-zerop i) 640 do (push (cons i x) sl))))) 641 (loop 642 with r = (sort sl #'> :key #'car) 643 with l = (length r) 644 with e = (car maxdim) 645 with m = (cadr maxdim) 646 with n = (caddr maxdim) 647 with u = (and e (* (- 1 e) 648 (loop 649 for (s . x) in r 650 sum (* s s)))) 651 with c = (if u 652 (loop 653 for (s . x) in r 654 count s 655 sum (* s s) into v 656 until (> v u)) 657 l) 658 with k = (cond ((and m (< c m) (/= c l)) 659 ;; (format *error-output* "hit mindim (~D)~%" c) 660 (min l m)) 661 ((and n (> c n)) 662 ;; (format *error-output* "hit maxdim (~D/~D)~%" c l) 663 n) 664 (t c)) 665 repeat k 666 for (s . x) in r 667 do (if (gethash x sh) 668 (incf (gethash x sh)) 669 (setf (gethash x sh) 1))) 670 ;; reduce the array dimensions 671 (loop 672 for s being the hash-keys in sh 673 using (hash-value d) 674 do 675 (let* ((r (svd-reduce-dimensions s d normalization)) 676 (n (svd-numbers r)) 677 (n1 (first n)) 678 (n2 (second n)) 679 (l1 (fused-index-joints n1 (first f))) 680 (l2 (fused-index-joints n2 (second f)))) 681 (push (make-segment :numbers n2 :dimension d) i1) 682 (push (make-segment :numbers n1 :dimension d) i2) 683 (push (make-segment :numbers n1 :dimension d) is1) 684 (push (make-segment :numbers n2 :dimension d) is2) 685 ;; first sectors 686 (dotimes (i (length l1)) 687 (let ((j (nth i l1))) 688 (push (make-sector 689 :numbers 690 (append (joint-numbers j) (list n2)) 691 :array 692 (array-reshape 693 (array-extract-subarray 694 (svd-u r) 695 (list (joint-subscript j) 0) 696 (list (joint-dimension j) d)) 697 (append (joint-dimensions j) (list d)))) 698 s1))) 699 ;; second sectors 700 (dotimes (i (length l2)) 701 (let ((j (nth i l2))) 702 (push (make-sector 703 :numbers 704 (append (list n1) (joint-numbers j)) 705 :array 706 (array-reshape 707 (array-extract-subarray 708 (svd-v r) 709 (list 0 (joint-subscript j)) 710 (list d (joint-dimension j))) 711 (append (list d) (joint-dimensions j)))) 712 s2))) 713 ;; singular values 714 (push (make-sector 715 :numbers (list n1 n2) 716 :array (diagonal-matrix (svd-s s) d)) 717 ss) 718 )) 719 ;; return decomposition 720 (values 721 (make-tensor :indices (append (first p) (list (sort-index i1))) 722 :sectors s1) 723 (make-tensor :indices (list (sort-index is1) (sort-index is2)) 724 :sectors ss) 725 (make-tensor :indices (append (list (sort-index i2)) (second p)) 726 :sectors s2)))) 727 728 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 729 730 ;; tensor-exponential 731 732 (defun tensor-permuted-exponential (tensor borders parameter) 733 (let* ((f (mapcar #'fused-index-hash-table 734 (partite-list (tensor-indices tensor) borders) 735 '(:normal :reverse))) 736 (h (make-hash-table :test 'equal))) 737 ;; add sectors; zero sectors will turn into unit sectors in the exponential 738 (loop 739 for k being the hash-keys in (first f) 740 do (let ((n (list k (list-- k)))) 741 (setf (gethash n h) (make-fused-array n f)))) 742 (dolist (s (tensor-sectors tensor)) 743 (let* ((p (partite-list (sector-numbers s) borders)) 744 (n (mapcar #'(lambda (l) (apply #'list-+ l)) p)) 745 (v (gethash n h))) 746 ;; insert sector array into the fused array 747 (array-insert-subarray v 748 (fused-array-subscripts p f) 749 (array-fuse (sector-array s) borders)))) 750 (make-tensor 751 :indices 752 (tensor-indices tensor) 753 :sectors 754 ;; todo: are zero sectors possible here? 755 (remove-zero-sectors 756 (loop 757 with l 758 for k being the hash-keys in h 759 using (hash-value v) 760 do 761 (setf v (hermitian-matrix-exponential v parameter)) 762 (let ((ml (mapcar #'fused-index-joints k f))) 763 (dolist (mi (multi-index-sequence (mapcar #'length ml))) 764 (let* ((j (mapcar #'nth mi ml))) 765 (push (make-sector 766 :numbers 767 (mapcan #'joint-numbers j) 768 :array 769 (array-reshape 770 (array-extract-subarray 771 v 772 (mapcar #'joint-subscript j) 773 (mapcar #'joint-dimension j)) 774 (mapcan #'joint-dimensions j))) 775 l)))) 776 finally (return l)))))) 777 778 (defun tensor-exponential (tensor groups parameter) 779 (unless (= (length groups) 2) 780 (error "Incorrect numbers of index groups.")) 781 (let* ((r (tensor-rank tensor)) 782 (o (apply #'append groups)) 783 (p (loop for i below r collect i))) 784 (tensor-permute 785 (tensor-permuted-exponential 786 (tensor-permute tensor (make-indices-permutation r o p)) 787 (list (length (first groups))) 788 parameter) 789 (make-indices-permutation r p o))))