Matlab: связать ID с набором данных (например, struct)? - PullRequest
2 голосов
/ 14 апреля 2019

Я разрабатываю определенную функцию для алгоритма моделирования конечных элементов высокого порядка в Matlab, и мне интересно, каков хороший способ реализации определенной задачи. Я полагаю, что столкнулся с довольно распространенной проблемой, но после некоторых копаний я не могу найти хорошего решения.

По сути, у меня есть длинный список идентификаторов (соответствующих определенным узлам в моей сетке), где каждый идентификатор связан с небольшим набором данных. Затем, когда я запускаю свой решатель, мне нужно получить доступ к данным, связанным с этими узлами, и обновить данные (несколько раз).

Итак, например, допустим, что это мой список этих конкретных узлов:

nodelist = [3 27 38] %(so these are my node ID's) 

Тогда для каждого узла у меня связан следующий набор данных

a (scalar)
b (5x5 double matrix)
c (10x1 double vector)

(a total of 36 double values associated with each node ID)

В действительности у меня, конечно, будет гораздо более длинный список идентификаторов узлов и несколько больший набор данных, связанный с каждым узлом (но все же только двойные скаляры, матрицы и векторы (без символов, строк и т. Д.)).

Подход 1

Итак, один из подходов, который я разработал, - это просто сохранить все в двумерной двойной матрице, а затем выполнить некоторую относительно сложную индексацию для доступа к моим данным, когда это необходимо. Для приведенного выше примера размер моей 2D-матрицы будет

size(2Dmat) = [length(nodelist), 36]

Скажем, я хотел получить доступ к b (3,3) для ID узла 27, я хотел бы получить доступ к 2Dmat (2,14).

В принципе, это работает, но код не очень чистый и читаемый из-за этой сложной индексации (не говоря уже о том, что когда я что-то изменяю в способе настройки набора данных, мне нужно заново настроить весь индексный код).

Подход 2

Другой подход заключается в использовании некоторой структуры для каждого узла в списке узлов:

a = 4.4;
b = rand(5,5);
c = rand(10,1);
s = struct('a',a,'b',b,'c',c)

И тогда я могу получить доступ к данным через, например, s.b (3,3) и т. Д. Но я просто не знаю, как связать структуру с идентификатором узла?

Подход 3

Последнее, о чем я мог подумать, это настроить какую-то базу данных SQL, но это кажется излишним. И, кроме того, мне нужно, чтобы мой код был максимально быстрым, поскольку мне нужно много раз обращаться к этим полям в наборах данных, связанных с этими выбранными узлами, и я полагаю, что выполнение некоторых запросов к базе данных замедлит работу.

Обратите внимание, что в конечном итоге я преобразую код из Matlab в C / C ++, поэтому я бы предпочел реализовать что-то, что не зависит в значительной степени от некоторых специфических функций Matlab.

Итак, есть мысли о том, как реализовать эту функциональность в чистом виде? Я надеюсь, что мой вопрос имеет смысл и заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 15 апреля 2019

Я думаю, что самым чистым решением, учитывая несмежный набор идентификаторов узлов, был бы подход 2, использующий контейнер карты , где ваш идентификатор узла является ключом (т. Е. Индексом) карты.Это может быть реализовано в MATLAB с использованием объекта containers.Map, а в C ++ - с использованием контейнера std::map.Например, вот как вы можете создавать и добавлять значения к карте узлов в MATLAB:

>> nodeMap = containers.Map('KeyType', 'double', 'ValueType', 'any');
>> nodelist = [3 27 38];
>> nodeMap(nodelist(1)) = struct('a', 4.4, 'b', rand(5, 5), 'c', rand(10, 1));
>> nodeMap(3)

ans = 

  struct with fields:

    a: 4.400000000000000
    b: [5×5 double]
    c: [10×1 double]

>> nodeMap(3).b(3,3)

ans =

   0.646313010111265

В C ++ вам потребуется определить структуру или класс (например, Node) для типа данных вхраниться на карте.Вот пример (... обозначает аргументы, передаваемые конструктору Node):

#include <map>

class Node {...};   // Define Node class
typedef std::map<int, Node> NodeMap;  // Using int for key type

int main()
{
  NodeMap map1;

  map1[3] = Node(...);  // Initialize and assign Node object
  map1.emplace(27, std::forward_as_tuple<...>);  // Create Node object in-place
}
2 голосов
/ 15 апреля 2019

Подход 2 является самым чистым и легко переводится на C ++. Для каждого узла у вас есть структура s, тогда:

data(nodeID) = s;

- это то, что называется структурным массивом. Вы проиндексированы как

data(id).b(3,3) = 0.0;

Это предполагает, что идентификаторы смежны или что в их значениях нет огромных пробелов. Но это всегда можно гарантировать, при необходимости легко перенумеровать идентификаторы узлов.


В C ++ у вас будет вектор структур:

struct Bla{
   double a;
   double b[3][3];
   double c[10];
};

std::vector<Bla> data(N);

Или в C:

Bla* data = malloc(sizeof(Bla)*N);

(и не забывайте free(data), когда закончите с ним).

Затем в C или C ++ вы получаете доступ к элементу следующим образом:

data[id].b[2][2] = 0.0;

Перевод очевиден, за исключением того, что индексирование начинается с 0 в C ++ и с 1 в MATLAB.


Обратите внимание, что этот метод имеет большие накладные расходы памяти, чем подход 1 в MATLAB, но не в C или C ++.

Подход 3 - плохая идея, он просто замедлит ваш код без каких-либо преимуществ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...