Matlab structure with Children that are arrays of structs, etc. - How do trace path to all children individually? - matlab

I have a Matlab structure, A, that has 3 fields. The first field is SignalName and the third field is Children. Children can either be empty or a Struct array with the same fields, and so on, to an arbitrary depth not immediately known to the user. SignalName is a character array which is the name of a signal.
I have written a recursive function (in Matlab) to retrieve all of the SignalName values for structures that have no Children, and it's pretty slick (I think), but I need to know the absolute path taken to arrive at said SignalName. I cannot figure this out in Matlab.
As an example:
A.SignalName = 'Things'
A.Children = <22x1 struct>
A.Children(1).SignalName = 'Places'
A.Children(1).Children = [8x1 struct]
This goes on for an unknown depth, and the length of the struct arrays is not immediately known. It is easy via recursion to 'dive' down and get all of the SignalNames belonging to Children with no further Children, but how do I trace the route I used to get there? My function would ideally return results as a signal name, and the path taken to said signal.
In my experience with other languages, it seems like something like A* or Breadth-First might help, but I'm not exactly searching for something. I want simply to map every node and the path to it, and I'm not sure how to do that with the strange data-structure I'm given.
Thanks for any help you all can provide!
EDIT: I wanted to provide the code to hopefully shed light on my issue. I can get the paths down to the deepest node, but any other nodes at that level leave me without a complete path to that specific location. This is what I need help with. I am using '*' as my delimiter for a regexp in my post-processing script to break up the strings in PATHS.
For two nodes at the same depth, I might get a full path like 'A.B.C.D.Signal1' for the first node, but the second would give me a path of 'D.Signal2', when what I need is 'A.B.C.D.Signal2'. If the path was the same to the 'D' level with every signal, I would just copy the path over, but I have multiple branches in this struct from each level, and I go 4 or 5 levels deep.
function [NAMES,PATHS]=FindSignals(A,TMP,TMP2)
persistent SigName;
persistent path;
SigName = TMP;
path = TMP2;
if(~isempty(A.Children)) % If this struct has Children
for i = 1:length(A.Children) % Iterate through the Children
nextStruct = A.Children(i);
path = strcat([path '*' A.SignalName]);
[NAMES,PATHS] = FindSignals(nextStruct,SigName,path); % Recurse
end
else % If this struct has no Children
path = strcat([path '*' A.SignalName '*']); % Finish the path to Child
SigName = char(SigName,A.SignalName); % Grab the signal name
NAMES = SigName;
PATHS = path;
end
end
Again, thanks for any help!
EDIT: 12/14/2015 - I'm still completely stuck on this. Could anyone please take a peek at my source code above? I am unsure how to tack on an absolute path to the recursive function call and allow it to be a full path for each node at the same depth, and then reset to the appropriate depth once I move up or down the 'tree'. Thanks.

Related

Matlab loop: ignores variable definition when loading something from directories

I am new to MATLAB and try to run a loop within a loop. I define a variable ID beforehand, for example ID={'100'}. In my loop, I then want to go to the ID's directory and then load the matfile in there. However, whenever I load the matfile, suddenly the ID definition gets overridden by all possible IDs (all folders in the directory where also the ID 100 is). Here is my code - I also tried fullfile, but no luck so far:
ID={'100'}
for subno=1:length(ID) % first loop
try
for sessno=1:length(Session) % second loop, for each ID there are two sessions
subj_name = ([ID{subno} '_' Session{sessno} '_vectors_SC.mat']);
cd(['C:\' ID{subno} '\' Session{sessno}]);
load(subj_vec_name) % the problem occurs here, when loading, not before
end
end
end
When I then check the length of the IDs, it is now not 1 (one ID, namely 100), but there are all possible IDs within the directory where 100 also lies, and the loop iterates again for all other possible IDs (although it should stop after ID 100).
You should always specify an output to load to prevent over-writing variables in your workspaces and polluting your workspace with all of the contents of the file. There is an extensive discussion of some of the strange potential side-effects of not doing this here.
Chances are, you have a variable named ID inside of the .mat file and it over-writes the ID variable in your workspace. This can be avoided using the output of load.
The output to load will contain a struct which can be used to access your data.
data = load(subj_vec_name);
%// Access variables from file
id_from_file = data.ID;
%// Can still access ID from your workspace!
ID
Side Note
It is generally not ideal to change directories to access data. This is because if a user runs your script, they may start in a directory they want to be in but when your program returns, it dumps them somewhere unexpected.
Instead, you can use fullfile to construct a path to the file and not have to change folders. This also allows your code to work on both *nix and Windows systems.
subj_name = ([ID{subno} '_' Session{sessno} '_vectors_SC.mat']);
%// Construct the file path
filepath = fullfile('C:', ID{subno}, Session{sessno}, subj_name);
%// Load the data without changing directories
data = load(filepath);
With the command load(subj_vec_name) you are loading the complete mat file located there. If this mat file contains the variable "ID" it will overwrite your initial ID.
This should not cause your outer for-loop to execute more than once. The vector 1:length(ID) is created by the initial for-loop and should not get overwritten by subsequent changes to length(ID).
If you insert disp(ID) before and after the load command and post the output it might be easier to help.

matlab: check which lines of a path are used - graphshortestpath

The related problem comes from the power Grid in Germany. I have a network of substations, which are connected according to the Lines. The shortest way from point A to B was calculated using the graphshortestpath function. The result is a path with the used substation ID's. I am interested in the Line ID's though, so I have written a sequential code to figure out the used Line_ID's for each path.
This algorithm uses two for loops. The first for-loop to access the path from a cell array, the second for-loop looks at each connection and searches the Line_ID from the array.
Question: Is there a better way of coding this? I am looking for the Line_ID's, graphshortestpath only returns the node ID's.
Here is the main code:
for i = i_entries
path_i = LKzuLK_path{i_entries};
if length(path_i) > 3 %If length <=3 no lines are used.
id_vb = 2:length(path_i) - 2;
for id = id_vb
node_start = path_i(id);
node_end = path_i(id+1);
idx_line = find_line_idx(newlinks_vertices, node_start, ...
node_end);
Zuordnung_LKzuLK_pathLines(ind2sub(size_path,i),idx_line) = true;
end
end
end
Note: The first and last enrty of path_i are area ID's, so they are not looked upon for the search for the Line_ID's
function idx_line = find_line_idx(newlinks_vertices, v_id_1, v_id_2)
% newlinks_vertices includes the Line_ID, and then the two connecting substations
% Mirror v_id's in newlinks_vertices:
check_links = [newlinks_vertices; newlinks_vertices(:,1), newlinks_vertices(:,3), newlinks_vertices(:,2)];
tmp_dist1 = find(check_links(:,2) == v_id_1);
tmp_dist2 = find(check_links(tmp_dist1,3) == v_id_2,1);
tmp_dist3 = tmp_dist1(tmp_dist2);
idx_line = check_links(tmp_dist3,1);
end
Note: I have already tried to shorten the first find-search routine, by indexing the links list. This step will return a short list with only relevant entries of the links looked upon. That way the algorithm is reduced of the first and most time consuming find function. The result wasn't much better, the calculation time was still at approximately 7 hours for 401*401 connections, so too long to implement.
I would look into Dijkstra's algorithm to get a faster implementation. This is what Matlab's graphshortestpath uses by default. The linked wiki page probably explains it better than I ever could and even lays it out in pseudocode!

stuck with my small code in matlab

I have problem with the following code:
.
.
.
a=zeros(1000,ctimes);
a1=zeros(1000,ctimes);
hold all
for i=num1:num2;
colors=Lines(i);
switch phantom
case 1
path=['E:\filename\'];
path1=['E:\filename2\'];
n=['S',num2str(emt),'_',num2str(i),'.m'];
d=load([path,name]);
a(:,i)=complex(d(:,2),d(:,3)));
n1=['S',num2str(emt),'_',num2str(i),'.m'];
d1=load([path1,name1]);
a1(:,i)=complex(d1(:,2),d1(:,3)));
the problem is that a(:,i) can not be defined. while there is no problem or with complex(d1(:,2),d1(:,3))) , can any expert body help me plz?!
thank you ...
Are you sure you are forming your file name correctly? You are doing something to create a variable n, but using a variable name when you form the path. Here are some recommended debugging steps:
1) make sure the file path is formed correctly:
filePath = fullfile(path, name);
disp(filePath);
The fullfile function concatenates elements of a file path & name, and takes care of using the right file path separator (good for portable code, stops you having to remember to add a / or \ to the end of a file path, etc).
2) check that d is loaded correctly:
clear d;
d = load(filePath);
disp(size(d));
3) check the size of the complex quantity you compute before assigning it to a(:,i):
temp = complex(d(:,2), d(:,3));
disp(size(temp));
By the time you have done these things, you should have found your problem (the dimensions of temp should be [1000 1] to match the size of a(:,i), of course).
As an aside, you should avoid using i as a variable name, especially when you are using complex numbers, since its built-in value is sqrt(-1). Thus, c = a + i * b; would create a complex number (a,b) and put it into c - until you change the meaning of i. A simple solution is to use ii. The same is true for j, by the way. It is one of the unfortunate design decisions in Matlab that you can overwrite built in values like that...

Matlab: dynamic name for structure

I want to create a structure with a variable name in a matlab script. The idea is to extract a part of an input string filled by the user and to create a structure with this name. For example:
CompleteCaseName = input('s');
USER WRITES '2013-06-12_test001_blabla';
CompleteCaseName = '2013-06-12_test001_blabla'
casename(12:18) = struct('x','y','z');
In this example, casename(12:18) gives me the result test001.
I would like to do this to allow me to compare easily two cases by importing the results of each case successively. So I could write, for instance :
plot(test001.x,test001.y,test002.x,test002.y);
The problem is that the line casename(12:18) = struct('x','y','z'); is invalid for Matlab because it makes me change a string to a struct. All the examples I find with struct are based on a definition like
S = struct('x','y','z');
And I can't find a way to make a dynamical name for S based on a string.
I hope someone understood what I write :) I checked on the FAQ and with Google but I wasn't able to find the same problem.
Use a structure with a dynamic field name.
For example,
mydata.(casename(12:18)) = struct;
will give you a struct mydata with a field test001.
You can then later add your x, y, z fields to this.
You can use the fields later either by mydata.test001.x, or by mydata.(casename(12:18)).x.
If at all possible, try to stay away from using eval, as another answer suggests. It makes things very difficult to debug, and the example given there, which directly evals user input:
eval('%s = struct(''x'',''y'',''z'');',casename(12:18));
is even a security risk - what happens if the user types in a string where the selected characters are system(''rm -r /''); a? Something bad, that's what.
As I already commented, the best case scenario is when all your x and y vectors have same length. In this case you can store all data from the different files into 2 matrices and call plot(x,y) to plot each column as a series.
Alternatively, you can use a cell array such that:
c = cell(2,nufiles);
for ii = 1:numfiles
c{1,ii} = import x data from file ii
c{2,ii} = import y data from file ii
end
plot(c{:})
A structure, on the other hand
s.('test001').x = ...
s.('test001').y = ...
Use eval:
eval(sprintf('%s = struct(''x'',''y'',''z'');',casename(12:18)));
Edit: apologies, forgot the sprintf.

Count the total elements of a path in Matlab

I'm working with a path with a lot of images and I need to make a for function to iterate all of them, and do stuff with each image. I made this funcion for this, but I miss one little detail:
myfiles = dir(fullfile('./mypath','*.png')); # path
for i=0:TOTAL_NUMBER_OF_IMAGES_OF_THE_PATHS
im = imread(['./mypath/', myfiles(i).name,'']); # im = current image
do stuff...
So, what can I put on that TOTAL_NUMBER_OF_IMAGES_OF_THE_PATHS?
Thanks in advance
You'll need the number of files for TOTAL_NUMBER_OF_ELEMENTS. dir returns a struct and you can get the number of elements using length or numel. So your for loop would read like:
for i=1:length(myfiles)
...
end