unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Matt Wette <matt.wette@gmail.com>
To: guile-user@gnu.org
Subject: Re: Matrix or array operations library
Date: Sun, 27 Jan 2019 10:41:57 -0800	[thread overview]
Message-ID: <b3003c8c-9ddd-d3f0-05a5-a27c4b383e67@gmail.com> (raw)
In-Reply-To: <2D1247B3-4B56-45C3-9AC4-5EA5E1B0858B@bluewin.ch>

So I tried an example using Guile to perform Gaussian elimination
(in situ, no column pivoting so unstable) using shared-arrays and
using explicit computation of offsets.  The explicit approach is
much more grungy but I'm guessing it does a lot less memory allocation.

Also, is it possible to get a pointer to the first element of an array
(i.e., it's #f64() root vector), for the purpose of using with FFI?

(use-modules ((srfi srfi-1) #:select (fold)))
(use-modules (srfi srfi-11))

;; === method 1: use share arrays

(define (axpy1 a x y)
   (let ((n (car (array-dimensions x))))
     (if (not (= n (car (array-dimensions y)))) (throw 'error))
     (let loop ((i 0))
       (when (< i n)
	(array-set! y (+ (* a (array-ref x i)) (array-ref y i)) i)
	(loop (1+ i))))))

;; modify A, b in-situ so that A is upper triangular
(define (reduce1 A b n)
   (let ((n-1 (1- n)))
     (let loop ((kl (iota n)))
       (when (pair? kl)
	(let* ((k (car kl))
	       (alpha (- (/ 1.0 (array-ref A k k))))
	       (x (make-shared-array A (lambda (j) (list k j)) n)))
	  (let loop1 ((i (1+ k)))
	    (when (< i n)
	      (let ((a (* alpha (array-ref A i k)))
		    (y (make-shared-array A (lambda (j) (list i j)) n)))
		(axpy1 a x y)
		(array-set! b (+ (* a (array-ref b k)) (array-ref b i)) i))
	      (loop1 (1+ i)))))
	(loop (cdr kl))))))
   
;; solve A*x = b for x where A is upper triangular
(define (bksolv1 A b x n)
   (let loop ((k (1- n)))
     (unless (negative? k)
       (let loop1 ((r 0.0) (j (1- n)))
	(cond
	 ((< k j)
	  (loop1 (+ r (* (array-ref A k j) (array-ref x j))) (1- j)))
	 (else
	  (array-set! x (/ (- (array-ref b k) r) (array-ref A k k)) k))))
       (loop (1- k)))))


;; === method 2: use root vector and computing offsets explicitly

;; based on root vectors
;; x, y are root vectors (from shared-array-root)
;; x0, y0 are starting indices
;; xi, yi are increments
(define (axpy2 n a x x0 xi y y0 yi)
   (let loop ((ix x0) (iy y0) (i 0))
     (when (< i n)
       (array-set! y (+ (* a (array-ref x ix)) (array-ref y iy)) iy)
       (loop (+ ix xi) (+ iy yi) (1+ i)))))

;; @deffn {Procedure} array-vec-model a vec-idx . idxs
;; Generate params for accessing a vector in an array.
;; Returned expression is
;; (values rv off inc)
;; where @code{rv} is the root-vector, @code{off} is the offset of the
;; first element and @code{inc} is the increment.
;; @end deffn
(define (array-vec-model a vec-idx . idxs)
   (let ((ic (shared-array-increments a)))
     (values (shared-array-root a)
	    (fold (lambda (bd ic ix of) (+ of (* ic (- ix (car bd)))))
		  (shared-array-offset a) (array-shape a) ic idxs)
	    (list-ref ic vec-idx))))

;; @deffn {Procedure} array-mat-model a row-idx col-idx . idxs
;; Generate params for accessing a vector in an array.
;; Returned expression is
;; (values rv off inc)
;; where @code{rv} is the root-vector, @code{off} is the offset of the
;; first element and @code{inc} is the increment.
;; @end deffn
(define (array-mat-model a row-idx col-idx . idxs)
   (let ((ic (shared-array-increments a)))
     (values (shared-array-root a)
	    (fold (lambda (bd ic ix of) (+ of (* ic (- ix (car bd)))))
		(shared-array-offset a) (array-shape a) ic idxs)
	    (list-ref ic row-idx)
	    (list-ref ic col-idx))))

;; modify A, b in-situ so that A is upper triangular
(define (reduce2 A b n)
   (let-values
       (((av a0 arinc acinc) (array-mat-model A 0 1 0 0))
        ((bv b0 binc) (array-vec-model b 0 0)))
     (let loop ((kl (iota n)) (akk a0) (bk b0))
       (when (pair? kl)
	(let* ((k (car kl))
	       (alpha (- (/ 1.0 (array-ref av akk)))))
	  (let loop1 ((i (1+ k)) (aik (+ akk arinc)) (bi (+ bk binc)))
	    (when (< i n)
	      (let ((a (* alpha (array-ref av aik))))
		(axpy2 (- n k) a av akk acinc av aik acinc)
		(array-set! bv (+ (* a (array-ref bv bk)) (array-ref bv bi)) bi))
	      (loop1 (1+ i) (+ aik arinc) (+ bi binc)))))
	(loop (cdr kl) (+ akk arinc acinc) (+ bk binc))))))

;; solve A*x = b for x where A is upper triangular
(define (bksolv2 A b x n)
   (let*-values
       (((av a00 arinc acinc) (array-mat-model A 0 1 0 0))
        ((bv b0 binc) (array-vec-model b 0 0))
        ((xv x0 xinc) (array-vec-model x 0 0))
        ((bn) (+ b0 (* (1- n) binc))))
     (let loop ((k (1- n))
	       (akn (+ a00 (* (1- n) arinc) (* (1- n) acinc)))
	       (xk (+ x0 (* (1- n) xinc))))
       (unless (negative? k)
	(let loop1 ((r 0.0) (j (1- n)) (akj akn) (bj bn))
	  (cond
	   ((< k j)
	    (loop1 (+ r (* (array-ref av akj) (array-ref x j)))
		   (1- j) (- akj acinc) (- bj binc)))
	   (else
	    (array-set! xv (/ (- (array-ref b j) r) (array-ref av akj)) xk))))
	(loop (1- k) (- akn arinc) (- xk xinc))))))


;; === example problem

(define A
   (list->typed-array
    'f64 2 '((11.0 1.2 1.3 1.4)
	    (2.1 22.0 2.3 2.4)
	    (3.1 3.2 33.0 3.4)
	    (4.1 4.2 4.3 44.0))))
(define b
   (list->typed-array
    'f64 1 '(4.0 3.0 2.0 1.0)))

(define x (make-typed-array 'f64 0.0 4))

;; expected result
(define x-soln
   (list->typed-array
    'f64 1 '(0.352856 0.103010 0.019728 -0.021913)))

(display "expect:\n") (vec-disp x-soln) (newline)

(when #f
   (reduce1 A b 4)
   ;;(display "A:\n") (mat-disp A)
   ;;(display "b:\n") (vec-disp b)
   (bksolv1 A b x 4)
   (display "method1:\n") (vec-disp x)
   )

(when #t
   (reduce2 A b 4)
   ;;(display "A:\n") (mat-disp A)
   ;;(display "b:\n") (vec-disp b)
   (bksolv2 A b x 4)
   (display "method2:\n") (vec-disp x)
   )




  reply	other threads:[~2019-01-27 18:41 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <mailman.32929.1546007691.1283.guile-user@gnu.org>
2018-12-28 20:23 ` Matrix or array operations library Daniel Llorens
2018-12-28 23:16   ` John Cowan
2018-12-29  0:17     ` Daniel Llorens
2019-01-27 18:41       ` Matt Wette [this message]
2018-12-28 23:24   ` Matt Wette
     [not found] <mailman.108.1545930019.12294.guile-user@gnu.org>
2018-12-27 18:43 ` Daniel Llorens
2018-12-27 21:24   ` John Cowan
2018-12-27 22:24   ` Matt Wette
     [not found] <mailman.73.1545757221.8862.guile-user@gnu.org>
2018-12-26 11:38 ` Zelphir Kaltstahl
2018-12-27 14:20   ` Matt Wette
2018-12-27 14:38     ` Mike Gran
     [not found] <c2172031-a0a6-9dd3-6ceb-7b6d94648475@gmail.com>
2018-12-24 22:01 ` Zelphir Kaltstahl
2018-12-24 23:06   ` Tk
2018-12-25  0:21   ` Matt Wette
2018-12-25 17:12   ` David Pirotte
2019-06-02 21:44   ` Linas Vepstas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b3003c8c-9ddd-d3f0-05a5-a27c4b383e67@gmail.com \
    --to=matt.wette@gmail.com \
    --cc=guile-user@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).