Matlab parfor error with biograph object: Struct contents reference from a non-struct array object

1 view (last 30 days)
Hi everyone,
I am struggling with a simple matlab parfor. I am using a biograph object representing a graph of interest. Since I have to compute a lot of shortest paths and the number of nodes is big, I thought it would be nice to use a parfor to speed up the computations. The code is as simple as this:
For the sake of the example, assume that we want to compute the shortest path from nodes 1, 2 and 3 to node 2.
cm = [0 1 1 0 0;1 0 0 1 1;1 0 0 0 0;0 0 0 0 1;1 0 1 0 0];
ids = {'M30931','L07625','K03454','M27323','M15390'};
bg = biograph(cm,ids);
workers = 3;
parpool('local', workers)
parfor i=1:3
[dist, pth, ~] = bg.shortestpath(i, 2);
end
The following error arises:
Struct contents reference from a non-struct array object.
I've already tried to call "bg.shortestpath(i, 2);" as a function but that didn't work. Maybe it has to do with the fact that biograph objects are treated like pointers by Matlab, meaning that if you execute,
bg2 = bg
, and then you modify any of the bg2's parameters, the changes are also reflected in bg.
I am aware that I could compute "bg.allshortestpaths" outside the loop and then extract the shortest path distance from there inside the loop but then, the path itself would remain unavailable.
I've read some related questions about this error but I don't know exactly how those relate with my biograph object data structure. I am sorry if this is a duplicate question but I am not keen on the Parallel Computing Toolbox and I feel very overwhelmed about how to approach this error. Maybe someone could point me in the right direction.
I am using MatlabR2017b.
Thank you in advance for the time you take in giving me some advice.
Regards,
Gabriel
  2 Comments
Siddharth Bhutiya
Siddharth Bhutiya on 16 Jan 2019
It seems to be something related to accessing the biograph object inside a parfor. What you can try is wrap it around a table object and then use it as follows
bg = biograph(cm,ids);
bgt = table(bg);
parfor i=1:3
[dist, pth, ~] = bgt.bg.shortestpath(i, 2);
end
Gabriel Otero
Gabriel Otero on 21 Jan 2019
Thanks for your answer. It is useful but I finally used the "graphshortestpath" function. I obtain the cross matrix from the biograph object using "bg.getweightmatrix" and pass the cross matrix directly to the function, instead of using the built in shortest path function in the biograph object.
Thank you again for your time.

Sign in to comment.

Accepted Answer

Gabriel Otero
Gabriel Otero on 21 Jan 2019
Edited: Gabriel Otero on 21 Jan 2019
I will answer my own question because this is the solution that best fits my needs, but you can take a look to the other answers in this thread that are also useful.
First, I extracted the graph's sparse cross matrix from the biograph object as follows:
crossMatrixSparse = bg.getweightmatrix;
Then, inside the parfor, I use the "graphshortestpath" function as
parfor i=1:3
[dist, pth, ~] = graphshortestpath(crossMatrixSparse, i, 2);
end
Regards,
Gabriel

More Answers (1)

Walter Roberson
Walter Roberson on 16 Jan 2019
You might need to use parfevalOnAll to create the object on all of the workers.
I can tell from the existence of set() in https://www.mathworks.com/help/bioinfo/ref/biographobject.html that biograph likely derives from handle class. As such there is only one "official" object that can be referenced under many names. That conflicts with parfor as parfor uses distinct address spaces: if you were to set() inside one of the workers then the change would have to affect all the references, but cannot in parfor because those other references are in a different process.
Using parfevalOnAll would create different instances on the different workers, and using set() on one of them would only affect that one worker.
  1 Comment
Gabriel Otero
Gabriel Otero on 21 Jan 2019
Edited: Gabriel Otero on 21 Jan 2019
Thanks for your answer Walter.
Anyway I found another solution which is using the "graphshortestpath" function.
First, I obtain the cross matrix from the biograph object using "bg.getweightmatrix" and then I pass the cross matrix directly to the "graphshortestpath" function, instead of using the built in shortest path function in the biograph object.
By the way I found that, this way, the execution time is reduced dramatically, probably due to the overhead that means using a biograph object.
Thank you anyway for your time.

Sign in to comment.

Categories

Find more on Parallel for-Loops (parfor) in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!