unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Damien Mattei <damien.mattei@gmail.com>
To: tomas@tuxteam.de
Cc: guile-user <guile-user@gnu.org>
Subject: Re: matrix library?
Date: Fri, 6 Oct 2023 20:33:36 +0200	[thread overview]
Message-ID: <CADEOade5p_AxHS=wBHpx97PNtzZivoG+87LqfMSQ9jBDe9SHzg@mail.gmail.com> (raw)
In-Reply-To: <ZSBIvlTlfgKuU913@tuxteam.de>

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



      reply	other threads:[~2023-10-06 18:33 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 message]

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='CADEOade5p_AxHS=wBHpx97PNtzZivoG+87LqfMSQ9jBDe9SHzg@mail.gmail.com' \
    --to=damien.mattei@gmail.com \
    --cc=guile-user@gnu.org \
    --cc=tomas@tuxteam.de \
    /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).