IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MATLAB Discussion :

passage de gros tableaux par adresse


Sujet :

MATLAB

  1. #1
    Membre éprouvé
    Avatar de ol9245
    Homme Profil pro
    Chercheur
    Inscrit en
    Avril 2007
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Avril 2007
    Messages : 985
    Points : 1 158
    Points
    1 158
    Billets dans le blog
    1
    Par défaut passage de gros tableaux par adresse
    Bonjour,

    J'ai toujours un peu de mal avec l'impossibilité de passer des arguments par référence. Ici, j'ai un tableau de taille (x*1000, x*1000) à passer à une fonction récursive pour qu'elle le modifie. Je suis donc obligé de passer ce tableau par référence.

    J'ai choisi l'option de la fonction interne (cf code ci-dessous). Je voudrais avoir des retours sur le bien-fondé de ce choix et sur les alternatives possibles.

    La fonction en question
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    function M = grassfire (M, R, seedrow, seedcol, neighb, done, docell)
    % Fonction générique qui applique de proche en proche un traitement sur les
    % mailles d'une matrice. Le traitement se propage comme un "feu de prairie" :
    % tout voisin non "brulé" prend feu. Le traitement s'arrête à la frontière
    % de la prairie.
    %
    % Notes :
    % ======
    % Récursion : La profondeur de récursion est au pire prof = numel(M).
    %       dans le cas général : prof = max(size(M)).
    % Caractère générique : le caractère générique de la fonction est assuré de
    %       plusieurs manières :
    %       1) par le passage en argument des fonction qui font effectivement les calculs.
    %       2) par le passage d'un tableau compagnon W qui peut être utilisé
    %       indépendamment du tableau M pour déterminer qui doit encore être traité
    %       et comment.
    %
    % Arguments :
    % ==========
    % M = le tableau à modifier
    % R = tableau annexe de même taille que M
    %       seedrow, seedcol = le point de départ de la récursion
    % [r, c] = neighb (r0, c0, size) = fonction qui retourne les
    %       index de ligne et de colonne des voisins de la maille (r0, c0) dans une
    %       matrice de taille size.
    % d = done (M, R, r, c) = fonction qui retourne vrai si la maille (r,c) est
    %       déjà traitée, faux sinon.
    % m = docell (M, R, r, c) = fonction qui retourne la nouvelle valeur à
    %       affecter à la maille M(r,c).
     
    grassfire_recurse (seedrow, seedcol, neighb, done, docell)
     
        function grassfire_recurse (seedrow, seedcol, neighb, done, docell)
            % docell the incoming cell
            M(seedrow, seedcol) = docell (M, R, seedrow, seedcol) ;
     
            % docell all the neighbors of the incoming seed
            [r, c] = neighb(seedrow, seedcol, size(M)) ;
     
            for k=1:numel(r)
                if ~done (M, R, r(k), c(k))
                    grassfire_recurse(r(k), c(k), neighb, done, docell) ;
                end
            end
        end
    end
    fonction de test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function grassfire_test
    close all
    clc
    [X, Y] = meshgrid(-10:10) ;
    D = X.^2  + Y.^2 ;
    Z = 10 .* D.^0.25 - 20 ;
    figure (1)
    subplot(1,2,1)
    surf(Z, 'linestyle', 'none'), axis equal
     
    Z2 = grassfire(Z, D, 11, 11, @neighbors, @done, @do) ;
     
    subplot(1,2,2)
    surf(Z2, 'linestyle', 'none'), axis equal
    end
     
    function d = done (M, R, r, c)
    fprintf('check %2d %2d %f\n', r, c, M(r,c)) ;
    d = (M(r,c)>=0) ;
    end
     
    function m = do(M, R, r, c)
    fprintf('do    %2d %2d %f\n', r, c, M(r,c)) ;
    m = 0 ;
    end
     
    function [r, c] = neighbors(seedrow, seedcol, s)
    r = seedrow + [-1 -1 -1 0 1 1 1 0] ;
    c = seedcol + [1 0 -1 -1 -1 0 1 1] ;
    ok = (r>0 & c>0 & r<=s(1) & c<=s(2)) ;
    r = r(ok) ;
    c = c(ok) ;
    end
    merci d'être passé par mon fil :-)
    "La vraie grandeur se mesure par la liberté que vous donnez aux autres, et non par votre capacité à les contraindre de faire ce que vous voulez." Larry Wall, concepteur de Perl.

  2. #2
    Rédacteur/Modérateur

    Avatar de Jerome Briot
    Homme Profil pro
    Freelance mécatronique - Conseil, conception et formation
    Inscrit en
    Novembre 2006
    Messages
    20 302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Freelance mécatronique - Conseil, conception et formation

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 302
    Points : 53 166
    Points
    53 166
    Par défaut
    Dans ton cas, dès que le process entre dans la fonction récursive, MATLAB crée une copie du tableau

    A ma connaissance, le seul moyen pour ne pas doubler la quantité de mémoire utilisée est de passer par un fichier MEX comme ici : Matlab mex in-place editing

    Mais c'est loin d'être trivial.
    Ingénieur indépendant en mécatronique - Conseil, conception et formation
    • Conception mécanique (Autodesk Fusion 360)
    • Impression 3D (Ultimaker)
    • Développement informatique (Python, MATLAB, C)
    • Programmation de microcontrôleur (Microchip PIC, ESP32, Raspberry Pi, Arduino…)

    « J'étais le meilleur ami que le vieux Jim avait au monde. Il fallait choisir. J'ai réfléchi un moment, puis je me suis dit : "Tant pis ! J'irai en enfer" » (Saint Huck)

  3. #3
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour,

    Il est possible de créer une classe héritant de handle afin de stocker ton tableau ; pour pas qu'il y ait recopie lors d'un passage en argument (comportement 'par pointeur')

  4. #4
    Rédacteur/Modérateur

    Avatar de Jerome Briot
    Homme Profil pro
    Freelance mécatronique - Conseil, conception et formation
    Inscrit en
    Novembre 2006
    Messages
    20 302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Freelance mécatronique - Conseil, conception et formation

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 302
    Points : 53 166
    Points
    53 166
    Par défaut
    Citation Envoyé par VV33D Voir le message
    Il est possible de créer une classe héritant de handle afin de stocker ton tableau ; pour pas qu'il y ait recopie lors d'un passage en argument (comportement 'par pointeur')
    Pourrais-tu nous montrer un exemple ?
    Ingénieur indépendant en mécatronique - Conseil, conception et formation
    • Conception mécanique (Autodesk Fusion 360)
    • Impression 3D (Ultimaker)
    • Développement informatique (Python, MATLAB, C)
    • Programmation de microcontrôleur (Microchip PIC, ESP32, Raspberry Pi, Arduino…)

    « J'étais le meilleur ami que le vieux Jim avait au monde. Il fallait choisir. J'ai réfléchi un moment, puis je me suis dit : "Tant pis ! J'irai en enfer" » (Saint Huck)

  5. #5
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Non désolé, je n'ai pas essayé, mais ayant fait des classes similaires, il suffit de faire une handle-classe qui contient la matrice dans un attribut .data.

    Il n'y aura pas copie lors d'un passage par arguments, mais attention aux syntaxes qui provoqueront une copie lorsque l'on touchera à instance.data.
    la surcharge de subsref/subsasgn peut éviter pas mal de ces cas (mais ca répond dans tous les cas au problème de passage par référence dans une fonction)

  6. #6
    Expert confirmé
    Avatar de duf42
    Homme Profil pro
    Formateur en informatique
    Inscrit en
    Novembre 2007
    Messages
    3 111
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Formateur en informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 111
    Points : 4 661
    Points
    4 661
    Par défaut
    Bonjour,

    Si j'ai bien tout compris ce qu'a proposé VV33D, il faut définir une classe comme celle-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    classdef MonTableau < handle
     
        properties
     
            data;
     
        end
     
    end
    Et ensuite on peut l'utiliser dans une fonction récursive sans avoir de copie mais bien un passage par référence:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    function ma_fcn_test(tableau)
     
    memory
    % Pour linux: !cat /proc/meminfo | grep -o "MemFree:[^\n]*"
     
    % Modification du tableau (qui entraine normalement une recopie de la variable)
    tableau.data(i) = 1;
     
    ma_fcn_test(tableau);
    A appeler avec un tableau de test:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    a = MonTableau;
    a.data = zeros(1e4);
    ma_fcn_test(a)
    Normalement pour cette exemple l'exécution s'arrête lorsqu'on atteint les 500 récursions sans augmentation significative de la mémoire.
    Par contre en enlevant le < handle de la définition de la classe MonTableau, il devrait y avoir un OUT OF MEMORY je pense.

    Je vous laisse tester et juger.

    Est-ce que ca correspond bien à ta proposition VV33D?

    Duf
    Simulink & Embedded Coder

    Au boulot : Windows 7 , MATLAB r2016b
    A la maison : ArchLinux mais pas MATLAB

  7. #7
    Membre éprouvé
    Avatar de ol9245
    Homme Profil pro
    Chercheur
    Inscrit en
    Avril 2007
    Messages
    985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Avril 2007
    Messages : 985
    Points : 1 158
    Points
    1 158
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Dut Voir le message
    Dans ton cas, dès que le process entre dans la fonction récursive, MATLAB crée une copie du tableau

    A ma connaissance, le seul moyen pour ne pas doubler la quantité de mémoire utilisée est de passer par un fichier MEX comme ici : Matlab mex in-place editing

    Mais c'est loin d'être trivial.
    Bonjour Dut, et merci de ton passage.

    En effet, je crée une copie à l'entrée de ma fonction principale (grass_fire). Mais de toutes façon c'est nécessaire à moins de faire comme tu l'indiques une modification de M "en place". Là je n'en ai pas besoin car je veux garder l'original et la version traitée. L'essentiel est surtout que je ne crée pas une copie à chaque appel à la fonction récursive interne (grassfire_recurse) car alors il y aurait une copie par maille, ce qui ferait sauter la mémoire.

    J'ai quand même regardé le lien très intéressant que tu m'as donné. J'ai essayé de mettre en application pour mes besoins du moment mais bon... ça fait +/-10 ans que je n'ai plus écrit une ligne de C++ et je suis rouillé ! dérouiller la machine + se familiariser avec l'API de Matlab, c'est pas de la tarte !

    @VV33D et duf42 : merci pour cette proposition. j'avais bien pensé à ce genre de solution mais (merci duf42) j'ai besoin de m'appuyer sur un exemple simple qui marche car je n'ai jamais encore programmé d'objets en matlab.
    "La vraie grandeur se mesure par la liberté que vous donnez aux autres, et non par votre capacité à les contraindre de faire ce que vous voulez." Larry Wall, concepteur de Perl.

  8. #8
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour,

    Oui Duf, c'est exactement ce à quoi je pensais.

    NB: si on a besoin de passer le .data en argument à des fonctions attendant un type builtin, on est obligé de faire fun(obj.data), ce qui va entrainer une copie. Redéfinir subsref() permet d'éviter certains de ces cas. La solution parfaite consisterait à hériter de handle et de double, mais matlab rend l'opération impossible !

    @ol9245 : Si tu as besoin d'une copie indépendante, il faut copier le .data (i.e copie_independante= obj.data);

Discussions similaires

  1. Passage par valeur / passage par adresse
    Par jeje99 dans le forum C++
    Réponses: 13
    Dernier message: 16/02/2006, 10h29
  2. passage par adresse
    Par cari dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 01/02/2006, 11h33
  3. probleme sur le passage d'argument par adresse
    Par ghostdog dans le forum C
    Réponses: 4
    Dernier message: 23/11/2005, 15h50
  4. Réponses: 2
    Dernier message: 19/07/2005, 11h12
  5. [Debutant(e)]passage par adresse?
    Par cap2fosse dans le forum Langage
    Réponses: 4
    Dernier message: 24/09/2004, 10h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo