unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* matrix library?
@ 2023-10-04  6:46 Damien Mattei
  2023-10-04  9:10 ` tomas
  0 siblings, 1 reply; 10+ messages in thread
From: Damien Mattei @ 2023-10-04  6:46 UTC (permalink / raw)
  To: guile-user

hello,
does anyone know if it exists a basic matrix library for Guile?
just need to multiply a matrix and a vector.

Damien



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-04  6:46 matrix library? Damien Mattei
@ 2023-10-04  9:10 ` tomas
  2023-10-04 11:36   ` Nala Ginrut
  0 siblings, 1 reply; 10+ messages in thread
From: tomas @ 2023-10-04  9:10 UTC (permalink / raw)
  To: Damien Mattei; +Cc: guile-user

[-- Attachment #1: Type: text/plain, Size: 354 bytes --]

On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
> hello,
> does anyone know if it exists a basic matrix library for Guile?
> just need to multiply a matrix and a vector.

Perhaps this thread from guile-user [1] has something for you

Cheers

[1] https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117

-- 
t

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-04  9:10 ` tomas
@ 2023-10-04 11:36   ` Nala Ginrut
  2023-10-04 15:42     ` Damien Mattei
  0 siblings, 1 reply; 10+ messages in thread
From: Nala Ginrut @ 2023-10-04 11:36 UTC (permalink / raw)
  To: tomas; +Cc: Damien Mattei, guile-user

And I'd mention AIScm which bound tensorflow APIs. It needs more love.

https://wedesoft.github.io/aiscm/


On Wed, Oct 4, 2023, 17:12 <tomas@tuxteam.de> wrote:

> On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
> > hello,
> > does anyone know if it exists a basic matrix library for Guile?
> > just need to multiply a matrix and a vector.
>
> Perhaps this thread from guile-user [1] has something for you
>
> Cheers
>
> [1]
> https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117
>
> --
> t
>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-04 11:36   ` Nala Ginrut
@ 2023-10-04 15:42     ` Damien Mattei
  2023-10-04 18:28       ` tomas
  0 siblings, 1 reply; 10+ messages in thread
From: Damien Mattei @ 2023-10-04 15:42 UTC (permalink / raw)
  To: Nala Ginrut; +Cc: tomas, guile-user

thank you. i will try to find a simple example in.

On Wed, Oct 4, 2023 at 1:36 PM Nala Ginrut <nalaginrut@gmail.com> wrote:
>
> And I'd mention AIScm which bound tensorflow APIs. It needs more love.
>
> https://wedesoft.github.io/aiscm/
>
>
> On Wed, Oct 4, 2023, 17:12 <tomas@tuxteam.de> wrote:
>>
>> On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
>> > hello,
>> > does anyone know if it exists a basic matrix library for Guile?
>> > just need to multiply a matrix and a vector.
>>
>> Perhaps this thread from guile-user [1] has something for you
>>
>> Cheers
>>
>> [1] https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117
>>
>> --
>> t



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-04 15:42     ` Damien Mattei
@ 2023-10-04 18:28       ` tomas
  2023-10-04 20:29         ` Damien Mattei
  0 siblings, 1 reply; 10+ messages in thread
From: tomas @ 2023-10-04 18:28 UTC (permalink / raw)
  To: Damien Mattei; +Cc: Nala Ginrut, guile-user

[-- Attachment #1: Type: text/plain, Size: 1711 bytes --]

On Wed, Oct 04, 2023 at 05:42:10PM +0200, Damien Mattei wrote:
> thank you. i will try to find a simple example in.
> 
> On Wed, Oct 4, 2023 at 1:36 PM Nala Ginrut <nalaginrut@gmail.com> wrote:
> >
> > And I'd mention AIScm which bound tensorflow APIs. It needs more love.
> >
> > https://wedesoft.github.io/aiscm/
> >
> >
> > On Wed, Oct 4, 2023, 17:12 <tomas@tuxteam.de> wrote:
> >>
> >> On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
> >> > hello,
> >> > does anyone know if it exists a basic matrix library for Guile?
> >> > just need to multiply a matrix and a vector.
> >>
> >> Perhaps this thread from guile-user [1] has something for you
> >>
> >> Cheers
> >>
> >> [1] https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117

That all said, if your case doesn't get much hairier,
it is fairly easy to navigate with Guile's arrays:

(define (dot v1 v2)
  "The dot product of v1 and v2"
  (let ((sum 0))
    (array-for-each
      (lambda (x1 x2)
        (set! sum (+ sum (* x1 x2))))
      v1 v2)
    sum))

(define (row m i)
  "The i-th row of m, as a vector"
  (make-shared-array m (lambda (j) (list i j)) (car (array-dimensions m))))

(define (mat* m v)
  "Left multiply matrix m and vector v"
  (let* ((height (cadr (array-dimensions m)))
         (res (make-typed-array 'f64 0 height)))
    (do ((i 0 (1+ i)))
        ((>= i height))
        (array-set! res (dot (row m i) v) i))
    res))


(define vec #1f64(1 2 1))
(define mat #2f64((0.5 0.5 0) (0 0.5 0.5) (-0.5 0 0.5)))

(mat* mat vec)

 => (1.5 1.5 0)

CAVEAT: only tested with this one example. Input value checking
left as an...

Cheers
-- 
t


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-04 18:28       ` tomas
@ 2023-10-04 20:29         ` Damien Mattei
  2023-10-05 14:47           ` Damien Mattei
  0 siblings, 1 reply; 10+ messages in thread
From: Damien Mattei @ 2023-10-04 20:29 UTC (permalink / raw)
  To: tomas; +Cc: Nala Ginrut, guile-user

yes i will re-implement that from scratch because i can not find
something easy in libraries to use.
I already made it for Racket/Scheme+:
(struct matrix-vect (v)) ;; matrix based on vector of vectors

(define (create-matrix-vect-by-function fct lin col)
  (matrix-vect (create-vector-2d fct lin col)))


;; return the line and column values of dimension
(define (dim-matrix-vect M)

  (when (not (matrix-vect? M))
    (error "argument is not of type matrix"))

  {v <+ (matrix-vect-v M)}
  {lin <+ (vector-length v)}
  {col <+ (vector-length {v[0]})}
  (values lin col))


(define (multiply-matrix-matrix M1 M2)

  {(n1 p1) <+ (dim-matrix-vect M1)}
  {(n2 p2) <+ (dim-matrix-vect M2)}

  (when {p1 ≠ n2} (error "matrix-by-vectors.* : matrix product
impossible, incompatible dimensions"))

  {v1 <+ (matrix-vect-v M1)}
  {v2 <+ (matrix-vect-v M2)}

  (define (res i j)
    (for/sum ([k (in-range p1)])
         {v1[i][k] * v2[k][j]}))

  {v <+ (create-vector-2d res n1 p2)}
  ;(display "v=") (display v) (newline)

  (matrix-vect v))


(define (vector->matrix-column v)
  (matrix-vect (vector-map (lambda (x) (make-vector 1 x))
               v)))

(define (matrix-column->vector Mc)
  {v <+ (matrix-vect-v Mc)}
  (vector-map (lambda (v2) {v2[0]})
          v))

(define (multiply-matrix-vector M v) ;; args: matrix ,vector ;  return vector
  {Mc <+ (vector->matrix-column v)}
  ;(display Mc)
  (matrix-column->vector (multiply-matrix-matrix M Mc)))


 there should be no difference for computation in Guile ,just that i
will use GOOPS instead of struct and that it should be a guile module
written in scheme+ syntax....
see it when finished....


On Wed, Oct 4, 2023 at 8:28 PM <tomas@tuxteam.de> wrote:
>
> On Wed, Oct 04, 2023 at 05:42:10PM +0200, Damien Mattei wrote:
> > thank you. i will try to find a simple example in.
> >
> > On Wed, Oct 4, 2023 at 1:36 PM Nala Ginrut <nalaginrut@gmail.com> wrote:
> > >
> > > And I'd mention AIScm which bound tensorflow APIs. It needs more love.
> > >
> > > https://wedesoft.github.io/aiscm/
> > >
> > >
> > > On Wed, Oct 4, 2023, 17:12 <tomas@tuxteam.de> wrote:
> > >>
> > >> On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
> > >> > hello,
> > >> > does anyone know if it exists a basic matrix library for Guile?
> > >> > just need to multiply a matrix and a vector.
> > >>
> > >> Perhaps this thread from guile-user [1] has something for you
> > >>
> > >> Cheers
> > >>
> > >> [1] https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117
>
> That all said, if your case doesn't get much hairier,
> it is fairly easy to navigate with Guile's arrays:
>
> (define (dot v1 v2)
>   "The dot product of v1 and v2"
>   (let ((sum 0))
>     (array-for-each
>       (lambda (x1 x2)
>         (set! sum (+ sum (* x1 x2))))
>       v1 v2)
>     sum))
>
> (define (row m i)
>   "The i-th row of m, as a vector"
>   (make-shared-array m (lambda (j) (list i j)) (car (array-dimensions m))))
>
> (define (mat* m v)
>   "Left multiply matrix m and vector v"
>   (let* ((height (cadr (array-dimensions m)))
>          (res (make-typed-array 'f64 0 height)))
>     (do ((i 0 (1+ i)))
>         ((>= i height))
>         (array-set! res (dot (row m i) v) i))
>     res))
>
>
> (define vec #1f64(1 2 1))
> (define mat #2f64((0.5 0.5 0) (0 0.5 0.5) (-0.5 0 0.5)))
>
> (mat* mat vec)
>
>  => (1.5 1.5 0)
>
> CAVEAT: only tested with this one example. Input value checking
> left as an...
>
> Cheers
> --
> t
>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-04 20:29         ` Damien Mattei
@ 2023-10-05 14:47           ` Damien Mattei
  2023-10-06 17:23             ` Damien Mattei
  0 siblings, 1 reply; 10+ messages in thread
From: Damien Mattei @ 2023-10-05 14:47 UTC (permalink / raw)
  To: tomas; +Cc: Nala Ginrut, guile-user

that is:

(define-method (* (M1 <matrix>) (M2 <matrix>))

  {(n1 p1) <+ (dim-matrix M1)}
  {(n2 p2) <+ (dim-matrix M2)}

  (when {p1 ≠ n2} (error "matrix.* : matrix product impossible,
incompatible dimensions"))

  {v1 <+ (matrix-v M1)}
  {v2 <+ (matrix-v M2)}

  (define (res i j)
    {sum <+ 0}
    (for ({k <+ 0} {k < p1} {k <- k + 1})
     {sum <- sum + v1[i][k] * v2[k][j]}))

  {v <+ (create-vector-2d res n1 p2)}
  ;(display "v=") (display v) (newline)

  (matrix v))

and the full code:
a matrix multiplication (could add + - but no needs in my code...)
with GOOPS and Scheme+ , without using the overload features of
scheme+ but the native ones of guile scheme:

(define-module (matrix)

  #:use-module (oop goops)

  #:use-module ((guile)
        #:select (*)
        #:prefix orig:)

  ;;#:use-module ((srfi srfi-43)) ;; vector

  #:export (<matrix>
        matrix?
        matrix
        matrix-v
        create-matrix-by-function
        dim-matrix)

  )


(include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/Scheme+.scm")

(include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/scheme-infix.scm")

(include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/assignment.scm")
(include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/apply-square-brackets.scm")

(include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/array.scm")
;; must know <- from assignment


(define-class <matrix> ()

  (v #:accessor matrix-v
     #:getter matrix-get-v
     #:setter matrix-set-v!
     #:init-keyword #:v)

  )


(define-method (matrix vinit)
  (make <matrix> #:v vinit))

(define-method (matrix? obj)
  (equal? (class-name (class-of obj)) (class-name <matrix>)))

;; (define M (create-matrix-by-function (lambda (l c) (+ l c)) 2 3))
;; $1 = #<<matrix> 1078a0a70>
(define (create-matrix-by-function fct lin col)
  (matrix (create-vector-2d fct lin col)))

;; return the line and column values of dimension
;; scheme@(guile-user)> (dim-matrix M)
;; $1 = 2
;; $2 = 3
(define (dim-matrix M)

  (when (not (matrix? M))
    (error "argument is not of type matrix"))

  {v <+ (matrix-v M)}
  {lin <+ (vector-length v)}
  {col <+ (vector-length {v[0]})}
  (values lin col))


;; scheme@(guile-user)> (define M1 (create-matrix-by-function (lambda
(l c) (+ l c)) 2 3))
;; scheme@(guile-user)> (define M2 (create-matrix-by-function (lambda
(l c) (- l c)) 3 2))
;; scheme@(guile-user)> (matrix-v M1)
;; $2 = #(#(0 1 2) #(1 2 3))
;; scheme@(guile-user)> (matrix-v M2)
;; $3 = #(#(0 -1) #(1 0) #(2 1))
;; (define M1*M2 {M1 * M2})
;; scheme@(guile-user)> (matrix-v M1*M2)
;; $2 = #(#(5 2) #(8 2))

(define-method (* (M1 <matrix>) (M2 <matrix>))

  {(n1 p1) <+ (dim-matrix M1)}
  {(n2 p2) <+ (dim-matrix M2)}

  (when {p1 ≠ n2} (error "matrix.* : matrix product impossible,
incompatible dimensions"))

  {v1 <+ (matrix-v M1)}
  {v2 <+ (matrix-v M2)}

  (define (res i j)
    {sum <+ 0}
    (for ({k <+ 0} {k < p1} {k <- k + 1})
     {sum <- sum + v1[i][k] * v2[k][j]}))

  {v <+ (create-vector-2d res n1 p2)}
  ;(display "v=") (display v) (newline)

  (matrix v))


and the test:

 (define M1 (create-matrix-by-function (lambda (l c) (+ l c)) 2 3))
;(define M2 (create-matrix-by-function (lambda (l c) (- l c)) 3 2))
(matrix-v M1)
 #(#(0 1 2) #(1 2 3))
(matrix-v M2)
 #(#(0 -1) #(1 0) #(2 1))
(define M1*M2 {M1 * M2})
 (matrix-v M1*M2)
 #(#(5 2) #(8 2))

additional function used:

;; create a vector of line and column with a function
(define (create-vector-2d fct lin col)
  {v <+ (make-vector lin)}
  ;;(display "ok") (newline)
  (for ({l <+ 0} {l < lin} {l <- l + 1})
       {v[l] <- (make-vector col)}
       (for ({c <+ 0} {c < col} {c <- c + 1})
        {v[l][c] <- (fct l c)}))
  v)

and a corrected version of :

(define-syntax for
   (lambda (stx)
     (syntax-case stx ()
       ((kwd (init test incrmt) body ...)
        (with-syntax ((BREAK (datum->syntax (syntax kwd) 'break))
                      (CONTINUE (datum->syntax (syntax kwd) 'continue)))
             (syntax
              (call/cc
               (lambda (escape)
             (let-syntax ((BREAK (identifier-syntax (escape))))
               init
               (let loop ((res 0)) ;; now we will return a result at
the end if no break but if we continue? what happens?
                 (if test
                 (begin
                   (call/cc
                    (lambda (next)
                      (set! res (let-syntax ((CONTINUE
(identifier-syntax (next))))
                          (let () ;; allow definitions
                            body ...)))))
                   incrmt
                   (loop res))
                 res)
                 ))))
              ) ;; close syntax

             )))))

note that expression

{sum <- sum + v1[i][k] * v2[k][j]}

is expanded as:

($nfx$ sum <- sum + ($bracket-apply$ ($bracket-apply$ v1 i) k) *
($bracket-apply$ ($bracket-apply$ v2 k) j))

which is not fast to evaluate,and slow down calculus on  intensive
computation, as the infix precedence procedure is evaluated each time
,even if it never change in the computation loop or never in program,
i'm working on an optimiser (written in scheme) of code before
evaluation , that modify the code (transform the infix expression with
precedence in prefix one definitively ) before it is passed to the
guile compiler.But it is another piece of code...

On Wed, Oct 4, 2023 at 10:29 PM Damien Mattei <damien.mattei@gmail.com> wrote:
>
> yes i will re-implement that from scratch because i can not find
> something easy in libraries to use.
> I already made it for Racket/Scheme+:
> (struct matrix-vect (v)) ;; matrix based on vector of vectors
>
> (define (create-matrix-vect-by-function fct lin col)
>   (matrix-vect (create-vector-2d fct lin col)))
>
>
> ;; return the line and column values of dimension
> (define (dim-matrix-vect M)
>
>   (when (not (matrix-vect? M))
>     (error "argument is not of type matrix"))
>
>   {v <+ (matrix-vect-v M)}
>   {lin <+ (vector-length v)}
>   {col <+ (vector-length {v[0]})}
>   (values lin col))
>
>
> (define (multiply-matrix-matrix M1 M2)
>
>   {(n1 p1) <+ (dim-matrix-vect M1)}
>   {(n2 p2) <+ (dim-matrix-vect M2)}
>
>   (when {p1 ≠ n2} (error "matrix-by-vectors.* : matrix product
> impossible, incompatible dimensions"))
>
>   {v1 <+ (matrix-vect-v M1)}
>   {v2 <+ (matrix-vect-v M2)}
>
>   (define (res i j)
>     (for/sum ([k (in-range p1)])
>          {v1[i][k] * v2[k][j]}))
>
>   {v <+ (create-vector-2d res n1 p2)}
>   ;(display "v=") (display v) (newline)
>
>   (matrix-vect v))
>
>
> (define (vector->matrix-column v)
>   (matrix-vect (vector-map (lambda (x) (make-vector 1 x))
>                v)))
>
> (define (matrix-column->vector Mc)
>   {v <+ (matrix-vect-v Mc)}
>   (vector-map (lambda (v2) {v2[0]})
>           v))
>
> (define (multiply-matrix-vector M v) ;; args: matrix ,vector ;  return vector
>   {Mc <+ (vector->matrix-column v)}
>   ;(display Mc)
>   (matrix-column->vector (multiply-matrix-matrix M Mc)))
>
>
>  there should be no difference for computation in Guile ,just that i
> will use GOOPS instead of struct and that it should be a guile module
> written in scheme+ syntax....
> see it when finished....
>
>
> On Wed, Oct 4, 2023 at 8:28 PM <tomas@tuxteam.de> wrote:
> >
> > On Wed, Oct 04, 2023 at 05:42:10PM +0200, Damien Mattei wrote:
> > > thank you. i will try to find a simple example in.
> > >
> > > On Wed, Oct 4, 2023 at 1:36 PM Nala Ginrut <nalaginrut@gmail.com> wrote:
> > > >
> > > > And I'd mention AIScm which bound tensorflow APIs. It needs more love.
> > > >
> > > > https://wedesoft.github.io/aiscm/
> > > >
> > > >
> > > > On Wed, Oct 4, 2023, 17:12 <tomas@tuxteam.de> wrote:
> > > >>
> > > >> On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
> > > >> > hello,
> > > >> > does anyone know if it exists a basic matrix library for Guile?
> > > >> > just need to multiply a matrix and a vector.
> > > >>
> > > >> Perhaps this thread from guile-user [1] has something for you
> > > >>
> > > >> Cheers
> > > >>
> > > >> [1] https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117
> >
> > That all said, if your case doesn't get much hairier,
> > it is fairly easy to navigate with Guile's arrays:
> >
> > (define (dot v1 v2)
> >   "The dot product of v1 and v2"
> >   (let ((sum 0))
> >     (array-for-each
> >       (lambda (x1 x2)
> >         (set! sum (+ sum (* x1 x2))))
> >       v1 v2)
> >     sum))
> >
> > (define (row m i)
> >   "The i-th row of m, as a vector"
> >   (make-shared-array m (lambda (j) (list i j)) (car (array-dimensions m))))
> >
> > (define (mat* m v)
> >   "Left multiply matrix m and vector v"
> >   (let* ((height (cadr (array-dimensions m)))
> >          (res (make-typed-array 'f64 0 height)))
> >     (do ((i 0 (1+ i)))
> >         ((>= i height))
> >         (array-set! res (dot (row m i) v) i))
> >     res))
> >
> >
> > (define vec #1f64(1 2 1))
> > (define mat #2f64((0.5 0.5 0) (0 0.5 0.5) (-0.5 0 0.5)))
> >
> > (mat* mat vec)
> >
> >  => (1.5 1.5 0)
> >
> > CAVEAT: only tested with this one example. Input value checking
> > left as an...
> >
> > Cheers
> > --
> > t
> >



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-05 14:47           ` Damien Mattei
@ 2023-10-06 17:23             ` Damien Mattei
  2023-10-06 17:49               ` tomas
  0 siblings, 1 reply; 10+ messages in thread
From: Damien Mattei @ 2023-10-06 17:23 UTC (permalink / raw)
  To: tomas; +Cc: Nala Ginrut, guile-user

and the rest of code for multiplying a matrix and a vector:

(define (vector->matrix-column v)
  (matrix (vector-map (lambda (i x)
            (make-vector 1 x))
              v)))

(define (matrix-column->vector Mc)
  {v <+ (matrix-v Mc)}
  (vector-map (lambda (i v2) {v2[0]})
          v))

;; scheme@(guile-user)> (define M1 (create-matrix-by-function (lambda
(l c) (+ l c)) 2 3))
;; scheme@(guile-user)> (matrix-v M1)
;; $1 = #(#(0 1 2) #(1 2 3))
;; scheme@(guile-user)> {M1 * #(1 2 3)}
;; $2 = #(8 14)
(define-method (* (M <matrix>) (v <vector>)) ;; args: matrix ,vector ;
 return vector
  {Mc <+ (vector->matrix-column v)}
  ;(display Mc)
  (matrix-column->vector {M * Mc}))


;; define getter,setter
(define (matrix-ref M lin col)
  {v <+ (matrix-v M)}
  {v[lin][col]})

(define (matrix-set! M lin col x)
  {v <+ (matrix-v M)}
  {v[lin][col] <- x})


;; >  (overload-square-brackets matrix-ref matrix-set!  (matrix?
number? number?))
;; >  (overload-square-brackets matrix-line-ref     (lambda (x) '())
(matrix? number?))
;; > $ovrld-square-brackets-lst$
;; '(((#<procedure:matrix?> #<procedure:number?>)
(#<procedure:matrix-line-ref> . #<procedure>))
;;   ((#<procedure:matrix?> #<procedure:number?> #<procedure:number?>)
(#<procedure:matrix-ref> . #<procedure:matrix-set!>)))
;; > (define Mv (matrix #(#(1 2 3) #(4 5 6))))
;; > Mv
;; #<matrix>
;; > (find-getter-for-overloaded-square-brackets (list Mv 1))
;; #<procedure:matrix-line-ref>
;; > {Mv[1 0]}
;; 4
;; > {Mv[1]}
;; '#(4 5 6)
;; > {Mv[1][0]}
;; 4
;; >
(define (matrix-line-ref M lin)
  {v <+ (matrix-v M)}
  {v[lin]})


(define (matrix-line-set! M lin vect-line)
  {v <+ (matrix-v M)}
  {v[lin] <- vect-line})

this allow also to indexes matrix as it is possible in Python and C++
by overloading the [ ] operator for the new type <matrix> :

;; overload [ ]
(overload-square-brackets matrix-ref matrix-set!  (matrix? number? number?))
(overload-square-brackets matrix-line-ref matrix-line-set! (matrix? number?))

scheme@(guile-user)> (define M (create-matrix-by-function (lambda (l
c) (+ l c)) 2 3))
scheme@(guile-user)>  (matrix-v M)
$1 = #(#(0 1 2) #(1 2 3))
scheme@(guile-user)> {M[1 2]}
$2 = 3
scheme@(guile-user)> {M[1][2]}
$3 = 3
scheme@(guile-user)> {M[1]}
$4 = #(1 2 3)

On Thu, Oct 5, 2023 at 4:47 PM Damien Mattei <damien.mattei@gmail.com> wrote:
>
> that is:
>
> (define-method (* (M1 <matrix>) (M2 <matrix>))
>
>   {(n1 p1) <+ (dim-matrix M1)}
>   {(n2 p2) <+ (dim-matrix M2)}
>
>   (when {p1 ≠ n2} (error "matrix.* : matrix product impossible,
> incompatible dimensions"))
>
>   {v1 <+ (matrix-v M1)}
>   {v2 <+ (matrix-v M2)}
>
>   (define (res i j)
>     {sum <+ 0}
>     (for ({k <+ 0} {k < p1} {k <- k + 1})
>      {sum <- sum + v1[i][k] * v2[k][j]}))
>
>   {v <+ (create-vector-2d res n1 p2)}
>   ;(display "v=") (display v) (newline)
>
>   (matrix v))
>
> and the full code:
> a matrix multiplication (could add + - but no needs in my code...)
> with GOOPS and Scheme+ , without using the overload features of
> scheme+ but the native ones of guile scheme:
>
> (define-module (matrix)
>
>   #:use-module (oop goops)
>
>   #:use-module ((guile)
>         #:select (*)
>         #:prefix orig:)
>
>   ;;#:use-module ((srfi srfi-43)) ;; vector
>
>   #:export (<matrix>
>         matrix?
>         matrix
>         matrix-v
>         create-matrix-by-function
>         dim-matrix)
>
>   )
>
>
> (include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/Scheme+.scm")
>
> (include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/scheme-infix.scm")
>
> (include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/assignment.scm")
> (include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/apply-square-brackets.scm")
>
> (include "/Users/mattei/Dropbox/git/Scheme-PLUS-for-Guile/array.scm")
> ;; must know <- from assignment
>
>
> (define-class <matrix> ()
>
>   (v #:accessor matrix-v
>      #:getter matrix-get-v
>      #:setter matrix-set-v!
>      #:init-keyword #:v)
>
>   )
>
>
> (define-method (matrix vinit)
>   (make <matrix> #:v vinit))
>
> (define-method (matrix? obj)
>   (equal? (class-name (class-of obj)) (class-name <matrix>)))
>
> ;; (define M (create-matrix-by-function (lambda (l c) (+ l c)) 2 3))
> ;; $1 = #<<matrix> 1078a0a70>
> (define (create-matrix-by-function fct lin col)
>   (matrix (create-vector-2d fct lin col)))
>
> ;; return the line and column values of dimension
> ;; scheme@(guile-user)> (dim-matrix M)
> ;; $1 = 2
> ;; $2 = 3
> (define (dim-matrix M)
>
>   (when (not (matrix? M))
>     (error "argument is not of type matrix"))
>
>   {v <+ (matrix-v M)}
>   {lin <+ (vector-length v)}
>   {col <+ (vector-length {v[0]})}
>   (values lin col))
>
>
> ;; scheme@(guile-user)> (define M1 (create-matrix-by-function (lambda
> (l c) (+ l c)) 2 3))
> ;; scheme@(guile-user)> (define M2 (create-matrix-by-function (lambda
> (l c) (- l c)) 3 2))
> ;; scheme@(guile-user)> (matrix-v M1)
> ;; $2 = #(#(0 1 2) #(1 2 3))
> ;; scheme@(guile-user)> (matrix-v M2)
> ;; $3 = #(#(0 -1) #(1 0) #(2 1))
> ;; (define M1*M2 {M1 * M2})
> ;; scheme@(guile-user)> (matrix-v M1*M2)
> ;; $2 = #(#(5 2) #(8 2))
>
> (define-method (* (M1 <matrix>) (M2 <matrix>))
>
>   {(n1 p1) <+ (dim-matrix M1)}
>   {(n2 p2) <+ (dim-matrix M2)}
>
>   (when {p1 ≠ n2} (error "matrix.* : matrix product impossible,
> incompatible dimensions"))
>
>   {v1 <+ (matrix-v M1)}
>   {v2 <+ (matrix-v M2)}
>
>   (define (res i j)
>     {sum <+ 0}
>     (for ({k <+ 0} {k < p1} {k <- k + 1})
>      {sum <- sum + v1[i][k] * v2[k][j]}))
>
>   {v <+ (create-vector-2d res n1 p2)}
>   ;(display "v=") (display v) (newline)
>
>   (matrix v))
>
>
> and the test:
>
>  (define M1 (create-matrix-by-function (lambda (l c) (+ l c)) 2 3))
> ;(define M2 (create-matrix-by-function (lambda (l c) (- l c)) 3 2))
> (matrix-v M1)
>  #(#(0 1 2) #(1 2 3))
> (matrix-v M2)
>  #(#(0 -1) #(1 0) #(2 1))
> (define M1*M2 {M1 * M2})
>  (matrix-v M1*M2)
>  #(#(5 2) #(8 2))
>
> additional function used:
>
> ;; create a vector of line and column with a function
> (define (create-vector-2d fct lin col)
>   {v <+ (make-vector lin)}
>   ;;(display "ok") (newline)
>   (for ({l <+ 0} {l < lin} {l <- l + 1})
>        {v[l] <- (make-vector col)}
>        (for ({c <+ 0} {c < col} {c <- c + 1})
>         {v[l][c] <- (fct l c)}))
>   v)
>
> and a corrected version of :
>
> (define-syntax for
>    (lambda (stx)
>      (syntax-case stx ()
>        ((kwd (init test incrmt) body ...)
>         (with-syntax ((BREAK (datum->syntax (syntax kwd) 'break))
>                       (CONTINUE (datum->syntax (syntax kwd) 'continue)))
>              (syntax
>               (call/cc
>                (lambda (escape)
>              (let-syntax ((BREAK (identifier-syntax (escape))))
>                init
>                (let loop ((res 0)) ;; now we will return a result at
> the end if no break but if we continue? what happens?
>                  (if test
>                  (begin
>                    (call/cc
>                     (lambda (next)
>                       (set! res (let-syntax ((CONTINUE
> (identifier-syntax (next))))
>                           (let () ;; allow definitions
>                             body ...)))))
>                    incrmt
>                    (loop res))
>                  res)
>                  ))))
>               ) ;; close syntax
>
>              )))))
>
> note that expression
>
> {sum <- sum + v1[i][k] * v2[k][j]}
>
> is expanded as:
>
> ($nfx$ sum <- sum + ($bracket-apply$ ($bracket-apply$ v1 i) k) *
> ($bracket-apply$ ($bracket-apply$ v2 k) j))
>
> which is not fast to evaluate,and slow down calculus on  intensive
> computation, as the infix precedence procedure is evaluated each time
> ,even if it never change in the computation loop or never in program,
> i'm working on an optimiser (written in scheme) of code before
> evaluation , that modify the code (transform the infix expression with
> precedence in prefix one definitively ) before it is passed to the
> guile compiler.But it is another piece of code...
>
> On Wed, Oct 4, 2023 at 10:29 PM Damien Mattei <damien.mattei@gmail.com> wrote:
> >
> > yes i will re-implement that from scratch because i can not find
> > something easy in libraries to use.
> > I already made it for Racket/Scheme+:
> > (struct matrix-vect (v)) ;; matrix based on vector of vectors
> >
> > (define (create-matrix-vect-by-function fct lin col)
> >   (matrix-vect (create-vector-2d fct lin col)))
> >
> >
> > ;; return the line and column values of dimension
> > (define (dim-matrix-vect M)
> >
> >   (when (not (matrix-vect? M))
> >     (error "argument is not of type matrix"))
> >
> >   {v <+ (matrix-vect-v M)}
> >   {lin <+ (vector-length v)}
> >   {col <+ (vector-length {v[0]})}
> >   (values lin col))
> >
> >
> > (define (multiply-matrix-matrix M1 M2)
> >
> >   {(n1 p1) <+ (dim-matrix-vect M1)}
> >   {(n2 p2) <+ (dim-matrix-vect M2)}
> >
> >   (when {p1 ≠ n2} (error "matrix-by-vectors.* : matrix product
> > impossible, incompatible dimensions"))
> >
> >   {v1 <+ (matrix-vect-v M1)}
> >   {v2 <+ (matrix-vect-v M2)}
> >
> >   (define (res i j)
> >     (for/sum ([k (in-range p1)])
> >          {v1[i][k] * v2[k][j]}))
> >
> >   {v <+ (create-vector-2d res n1 p2)}
> >   ;(display "v=") (display v) (newline)
> >
> >   (matrix-vect v))
> >
> >
> > (define (vector->matrix-column v)
> >   (matrix-vect (vector-map (lambda (x) (make-vector 1 x))
> >                v)))
> >
> > (define (matrix-column->vector Mc)
> >   {v <+ (matrix-vect-v Mc)}
> >   (vector-map (lambda (v2) {v2[0]})
> >           v))
> >
> > (define (multiply-matrix-vector M v) ;; args: matrix ,vector ;  return vector
> >   {Mc <+ (vector->matrix-column v)}
> >   ;(display Mc)
> >   (matrix-column->vector (multiply-matrix-matrix M Mc)))
> >
> >
> >  there should be no difference for computation in Guile ,just that i
> > will use GOOPS instead of struct and that it should be a guile module
> > written in scheme+ syntax....
> > see it when finished....
> >
> >
> > On Wed, Oct 4, 2023 at 8:28 PM <tomas@tuxteam.de> wrote:
> > >
> > > On Wed, Oct 04, 2023 at 05:42:10PM +0200, Damien Mattei wrote:
> > > > thank you. i will try to find a simple example in.
> > > >
> > > > On Wed, Oct 4, 2023 at 1:36 PM Nala Ginrut <nalaginrut@gmail.com> wrote:
> > > > >
> > > > > And I'd mention AIScm which bound tensorflow APIs. It needs more love.
> > > > >
> > > > > https://wedesoft.github.io/aiscm/
> > > > >
> > > > >
> > > > > On Wed, Oct 4, 2023, 17:12 <tomas@tuxteam.de> wrote:
> > > > >>
> > > > >> On Wed, Oct 04, 2023 at 08:46:02AM +0200, Damien Mattei wrote:
> > > > >> > hello,
> > > > >> > does anyone know if it exists a basic matrix library for Guile?
> > > > >> > just need to multiply a matrix and a vector.
> > > > >>
> > > > >> Perhaps this thread from guile-user [1] has something for you
> > > > >>
> > > > >> Cheers
> > > > >>
> > > > >> [1] https://lists.gnu.org/archive/html/guile-user/2018-12/threads.html#00117
> > >
> > > That all said, if your case doesn't get much hairier,
> > > it is fairly easy to navigate with Guile's arrays:
> > >
> > > (define (dot v1 v2)
> > >   "The dot product of v1 and v2"
> > >   (let ((sum 0))
> > >     (array-for-each
> > >       (lambda (x1 x2)
> > >         (set! sum (+ sum (* x1 x2))))
> > >       v1 v2)
> > >     sum))
> > >
> > > (define (row m i)
> > >   "The i-th row of m, as a vector"
> > >   (make-shared-array m (lambda (j) (list i j)) (car (array-dimensions m))))
> > >
> > > (define (mat* m v)
> > >   "Left multiply matrix m and vector v"
> > >   (let* ((height (cadr (array-dimensions m)))
> > >          (res (make-typed-array 'f64 0 height)))
> > >     (do ((i 0 (1+ i)))
> > >         ((>= i height))
> > >         (array-set! res (dot (row m i) v) i))
> > >     res))
> > >
> > >
> > > (define vec #1f64(1 2 1))
> > > (define mat #2f64((0.5 0.5 0) (0 0.5 0.5) (-0.5 0 0.5)))
> > >
> > > (mat* mat vec)
> > >
> > >  => (1.5 1.5 0)
> > >
> > > CAVEAT: only tested with this one example. Input value checking
> > > left as an...
> > >
> > > Cheers
> > > --
> > > t
> > >



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-06 17:23             ` Damien Mattei
@ 2023-10-06 17:49               ` tomas
  2023-10-06 18:33                 ` Damien Mattei
  0 siblings, 1 reply; 10+ messages in thread
From: tomas @ 2023-10-06 17:49 UTC (permalink / raw)
  To: Damien Mattei; +Cc: Nala Ginrut, guile-user

[-- Attachment #1: Type: text/plain, Size: 290 bytes --]

On Fri, Oct 06, 2023 at 07:23:10PM +0200, Damien Mattei wrote:
> and the rest of code for multiplying a matrix and a vector:

[...]

I haven't looked at all the details, but... isn't  multiplying a
matrix with a vector just a special case of matrix multiplication?

Cheers
-- 
t

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: matrix library?
  2023-10-06 17:49               ` tomas
@ 2023-10-06 18:33                 ` Damien Mattei
  0 siblings, 0 replies; 10+ messages in thread
From: Damien Mattei @ 2023-10-06 18:33 UTC (permalink / raw)
  To: tomas; +Cc: guile-user

in maths there is a "philosophical" difference between a vector and
column-matrix.

for simplicity in my code i prefer to be able to multiply matrix and
vector directly as vector is a predefined type in scheme, not
matrix.And get as result a vector too.

but of course the solution is to convert the vector in matrix-column
and use the already defined and already overloaded multiplication of
two matrix:

(define-method (* (M <matrix>) (v <vector>)) ;; args: matrix ,vector ;
 return vector
  {Mc <+ (vector->matrix-column v)}
  (matrix-column->vector {M * Mc}))

in fact i'm porting and testing a python code to scheme+ in Racket
(already done) and Guile :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Matrix.py
The class Matrix.
Derived from:
exo_mat2.py
La classe Matrix : algèbre des matrices de format quelconque, sans numpy
"""

# D. Mattei

from multimethod import multimethod

from typing import Union,Callable

from collections.abc import Iterable


class MatError(Exception):     # juste pour la lisibilité des exceptions
    pass


Numeric = Union[float, int]


# m1=Matrix([[1,3],[-2,4],[0,-1]])
# m2=Matrix([[1],[2]])
# m3=Matrix([[1,3],[-2,4],[0,-1]])
# >>> m1*m2*m3
# Matrix.py : __mul__(Matrix,Matrix)
# # Matrix constructor Matrix (function,Numeric,Numeric) #
# Matrix.py : __mul__(Matrix,Matrix)
# # Matrix constructor Matrix (function,Numeric,Numeric) #
#       7.00         21.00
#       6.00         18.00
#      -2.00         -6.00
# Matrix @ 0x7fca8d71edd0
class Matrix:
    '''Construct an object Matrix.'''

    # >>> m1=Matrix(2,3)
    @multimethod
    def __init__(self,n : Numeric,p : Numeric): # lines, columns
        '''Construit un objet matrice de type Matrix, d'attributs le
format self.dim
        et la liste architecturée en liste de listes de même longueur.
Exemples :
            m = Matrix([[1,3],[-2,4],[0,-1]])  à 3 lignes et 2 colonnes
            m = Matrix(lambda i,j: i+j,3,5)    à 3 lignes et 5 colonnes'''

        if __debug__:
            print("# Matrix constructor Matrix (Numeric,Numeric) #")

        __init__(lambda i,j: 0,n,p) # return a Zero matrix



    @multimethod
    def __init__(self,f : Callable,n : Numeric,p : Numeric):

        if __debug__:
            print("# Matrix constructor Matrix (function,Numeric,Numeric) #")

        self.L = [[f(i,j) for j in range(p)] for i in range(n)]


    @multimethod
    def __init__(self,Lf : list):

        if __debug__:
            print("# Matrix constructor Matrix,list #")

        if any(map(lambda x:type(x) != list,Lf)) :
            raise MatError('Matrix : on attend une liste de listes !')
        p = len(Lf[0])
        if any(map(lambda x:len(x)!=p,Lf)) :
            raise MatError('Matrix : on attend une liste de listes de
même longueur !')
        self.L = Lf         # la liste qui contient les éléments de matrice



    def dim(self):
        '''Retourne le format de la matrice courante.'''
        n = len(self.L)
        if n == 0:
            raise MatError('Matrice vide !')
        return (n,len(self.L[0]))



    # m1=Matrix(lambda i,j : i+j, 5,2)
    # # Matrix constructor Matrix (function,Numeric,Numeric) #
    # m1
    #       0.00          1.00
    #       1.00          2.00
    #       2.00          3.00
    #       3.00          4.00
    #       4.00          5.00
    # Matrix @ 0x105ae03d0

    # print(m1)
    #       0.00          1.00
    #       1.00          2.00
    #       2.00          3.00
    #       3.00          4.00
    #       4.00          5.00
    def __repr__(self):
        '''Retourne une chaine formatée avec colonnes alignées représentant
        la matrice m.'''

        return self.__str__() + '\nMatrix @ {} \n'.format(hex(id(self)))



    # >>> print(m)
    def __str__(self):

        '''Retourne une chaine formatée avec colonnes alignées représentant
        la matrice m.'''

        def texte(x):
            return '{:10.2f}'.format(x)   # précision limitée à l'affichage...

        (n,p) = self.dim()
        L = ['\t'.join(list(map(texte,self.L[i]))) for i in range(n)]

        return '\n'.join(L)



    def __getitem__(self,i):        # pour pouvoir écrire m[i] pour la ligne i
        return self.L[i]            # et m[i][j] pour l'élément en
ligne i et colonne j

    def __setitem__(self, i, data):
          self.A[i] = data

    def lig(self,i):                # m.lig(i) <==> m[i]
        '''Retourne la ligne i >= 0 de la matrice sous forme de liste plate.'''
        return self.L[i]

    def col(self,j):
        '''Retourne la colonne j >= 0 de la matrice sous forme de
liste plate.'''
        (n,_) = self.dim()
        return [self.L[i][j] for i in range(n)]


    def __add__(self,m2):
        '''Retourne la somme de la matrice courante et d'une matrice m2
        de même format.'''
        (n,p) = self.dim()
        if m2.dim() != (n,p):
            raise MatError('mat_sum : Mauvais formats de matrices !')
        L = self.L ; L2 = m2.L
        return Matrix(lambda i,j : L[i][j] + L2[i][j],n,p)

    def __sub__(self,m2):
        '''Retourne la différence entre la matrice courante et une matrice
        m2 de même format.'''
        return self + m2.mul(-1)


    def mul(self,k):
        '''Retourne le produit externe du nombre k par la matrice m.'''
        (n,p) = self.dim()
        return Matrix(lambda i,j : k*self.L[i][j],n,p)


    # R  : multiplicand
    # matrix multiplication by number

    @multimethod
    def __rmul__(self, m : Numeric): #  self is at RIGHT of
multiplication operand : m * self
        '''Retourne le produit externe du nombre par la matrice'''
        if __debug__:
            print("Matrix.py : __rmul__(Matrix,Numeric)")

        return self.mul(m)


    def app(self,v):                           # v = [a,b,c,d]
        '''Retourne l'application de la matrice self au vecteur v vu
comme une liste
        plate. Le résultat est aussi une liste plate.'''

        if __debug__:
            print("Matrix.py : app")


        # transformation de la liste v en matrice uni-colonne
        mv = Matrix(list(map(lambda x:[x],v)))          # mv = [[a],[b],[c],[d]]
        # l'application n'est autre qu'un produit de matrices
        res = self * mv         # objet de type Mat
        #print("app : res =\n"); print(res)
        res = res.L             # objet de type list
        # et on ré-aplatit la liste
        return list(map(lambda L:L[0],res))



    # R  : multiplicand
    # m1=Matrix(lambda i,j : i+j, 5,2)
    # # Matrix constructor Matrix (function,Numeric,Numeric) #
    # m1*(-2,-3.5)
    # Matrix.py : __mul__(Matrix,Iterable)
    # # Matrix constructor Matrix,list #
    # Matrix.py : __mul__(Matrix,Matrix)
    # # Matrix constructor Matrix (function,Numeric,Numeric) #
    # [-3.5, -9.0, -14.5, -20.0, -25.5]
    @multimethod
    def __mul__(self, R : Iterable): #  self is at LEFT of
multiplication operand : self * R = Matrix * R, R is at Right

        if __debug__:
            print("Matrix.py : __mul__(Matrix,Iterable)")

        return self.app(R)



    # R  : multiplicand
    # matrix multiplication
    # m2=Matrix([[-2],[-3.5]])
    # # Matrix constructor Matrix,list #
    # m2
    #      -2.00
    #      -3.50
    # Matrix @ 0x10127f490

    # m1*m2
    # Matrix.py : __mul__(Matrix,Matrix)
    # # Matrix constructor Matrix (function,Numeric,Numeric) #
    #      -3.50
    #      -9.00
    #     -14.50
    #     -20.00
    #     -25.50
    # Matrix @ 0x1012a7810
    @multimethod
    def __mul__(self, m2 : object): #  self is at LEFT of
multiplication operand : self * m2 = Matrix * m2 = Matrix * Matrix, m2
is at Right of operator

        if __debug__:
            print("Matrix.py : __mul__(Matrix,Matrix)")

        (n1,p1) = self.dim()
        (n2,p2) = m2.dim()
        if p1 != n2 : raise MatError('Produit de matrices impossible !')
        def res(i,j) :              # l'élément en ligne i et colonne
j du résultat
            return sum(self.L[i][k] * m2.L[k][j] for k in range(p1))
        # le produit aura pour format (n1,p2)
        return Matrix(res,n1,p2)



On Fri, Oct 6, 2023 at 7:49 PM <tomas@tuxteam.de> wrote:
>
> On Fri, Oct 06, 2023 at 07:23:10PM +0200, Damien Mattei wrote:
> > and the rest of code for multiplying a matrix and a vector:
>
> [...]
>
> I haven't looked at all the details, but... isn't  multiplying a
> matrix with a vector just a special case of matrix multiplication?
>
> Cheers
> --
> t



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-10-06 18:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-04  6:46 matrix library? Damien Mattei
2023-10-04  9:10 ` tomas
2023-10-04 11:36   ` Nala Ginrut
2023-10-04 15:42     ` Damien Mattei
2023-10-04 18:28       ` tomas
2023-10-04 20:29         ` Damien Mattei
2023-10-05 14:47           ` Damien Mattei
2023-10-06 17:23             ` Damien Mattei
2023-10-06 17:49               ` tomas
2023-10-06 18:33                 ` Damien Mattei

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).