Containers.Map and struct with dynamic field names not supported in code generation

Hello there,
Now I have finished a hybrid A* Planner in Matlab and would like C++ code generation. (though there is plannerhybridastar embedded in Matlab.) In this planner is containers.Map used for open set. But the coder said it does not support.
It’s not cool but I am not so surprised. I try the workaround with struct array. The field name is the ID of nodes and the value is node (instantiated object). With “isfield” it can check, whether a ID in struct exist. It works in Matlab
but again the code generation fails with error:
Non-constant expression or empty matrix. This expression must be constant because its value determines the size or class of some expression.
at following:
obj.structName.(fieldName)= node;
% assign “node” to field name in structName
In which fieldName is a variable with type char and will be updated. After a small study the reason should be, Coder does not support accessing the fields of a structure using dynamic field names.
But in my opinion, it is necessary that “fieldName” as dynamic, because it is unknown and will be assigned.
Now I am confused and do not know if there is workaround or solution. Actually, what I need is something which is supported by code generation and can store key and value accordingly. As above, the value is instantiated object.
Do you have some ideas and could you help me? Thanks in advance.
Best Regards
Yan

 Accepted Answer

Struct array. One of the fields is the node ID, and the other is the node value. Instead of checking whether the node exists using isfield(), check whether the key is present in the node id list.
For efficiency, use a tree strategy, or at least a sorted list that you can do a binary search on. Or a hash if you expect a lot of them.
Use an external library if you like: the external data structure could take in IDs and the "value" associated could be the linear index into the struct array.

5 Comments

Hello Mr. Roberson,
thank you for the reply. Sorry I have not exactly described and struct array is used, as pic. following.
As you said, ID as field Name, value as node, with "isfield" is able to check, whether the node in the struct array. With updated "fieldName" new nodes are in struct array pushed. It works in Matlab:
obj.structName.(fieldName)= node;
% assign “node” to field name in structName
Unfortunately the code generation does not work. Probably because, the coder does not support accessing the fields of a structure using dynamic field names. In my opinion, it is necessary that “fieldName” as dynamic, because it is unknown and will be assigned. For this, I wonder if there is workaround or solution.
Best regards
Yan
[~, idx] = ismember(fieldName, obj.structName.fieldNames);
if idx == 0
idx = length(obj.structName.fieldNames) + 1;
obj.structName.fieldNames{idx} = fieldName;
obj.structName.nodes(idx) = empty_node;
end
obj.structName.nodes(idx) = node;
In its present form, it does rely upon obj.structName.fieldNames being growable. It does not actually rely upon obj.structName.nodes being growable -- could have been pre-allocated to maximum size.
Hello Mr. Roberson,
thank you for the exciting idea.
It works in matlab und in code generation threre is still error, such as "This structure does not have a field 'fieldName'", probably because of initiating and pre-allocation. Could I have 2 questions?
  1. data type of "node": currently the nodes (OptimNode in the pic.) are array of objects. It seems OK for Matlab. Is this supported in code generation? If allowed, how to initiate or pre-allocate?
  2. if the max. size of the structure is defined in pre-allocation, the line "idx = length(obj.structName.fieldNames) + 1;" should be reworked, is it right? As array length is fixed, then appending at the end of the array does not suit.
Best regards.
Yan
"This structure does not have a field 'fieldName'"
My code never uses fieldName as a field name.
if the max. size of the structure is defined in pre-allocation, the line "idx = length(obj.structName.fieldNames) + 1;" should be reworked, is it right?
Right. You would instead keep a counter of the number of nodes actually in use.
num_in_use = obj.structName.num_in_use;
[~, idx] = ismember(fieldName, obj.structName.fieldNames(1:num_in_use));
if idx == 0
idx = num_in_use + 1;
if idx > length(obj.structName.nodes)
error('Node table full trying to insert "%s"', fieldName);
end
obj.structName.num_in_use = idx;
obj.structName.fieldNames{idx} = fieldName;
obj.structName.nodes(idx) = empty_node;
end
obj.structName.nodes(idx) = node;
Thank you for the patience and cool idea. It works! and I have also learned, it is necessary to pre-allocate the struct in constructor.
Best regards
Yan

Sign in to comment.

More Answers (0)

Categories

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!