Evaluate cells of strings in a cell array - arrays

I have a cell array containing strings and cells, similar to this:
theCellArray = {{'aa1' {'bb'; 'cc'}}; {'aa2' {'dd'; 'ee'}}};
Now I would like to be able to concatenate the names and get something similar to this :
aa1.bb
aa1.cc
aa2.dd
aa2.ee
The number of element might change (so for aa1, there might be bb, cc, dd, ee, etc).
I tried various things, but I'm always unable to make Matlab evaluate the second step of string (the one containing bb, cc...). Any ideas?
EDIT:
There might be more than 2 levels, so theCellArray could be :
theCellArray = {{'aa1' {'bb' {'b1' {'b11' 'b12'} 'b2'}; 'cc'}}; {'aa2' {'dd'; 'ee'}}};
theCellArray is like a tree, so the number of level is unknown.

Here is a recursive solution:
function t = recCat(s)
if ~iscell(s)
t = s;
elseif size(s,1) > 1,
t = [recCat(s(1,:)); recCat(s(2:end,:))];
elseif size(s,2) > 1,
t0 = cellfun(#(x) strcat('.', x), ...
cellfun(#recCat, s(2:end), 'UniformOutput', false), ...
'UniformOutput', false);
t = strcat(s{1}, t0{:});
elseif ischar(s{1})
t = s;
else
t = recCat(s{1});
end
end
Here is the result for first example:
>> theCellArray = {{'aa1' {'bb'; 'cc'}}; {'aa2' {'dd'; 'ee'}}};
>> recCat(theCellArray)
ans =
'aa1.bb'
'aa1.cc'
'aa2.dd'
'aa2.ee'
The second, as it stands now fails because of dimension issues in concatenation. I put 'bb' {'b1' {'b11' 'b12'} 'b2'} into another cell so that it has the same number of columns as 'cc' then you get
>> theCellArray = {{'aa1' {{'bb' {'b1' {'b11' 'b12'} 'b2'}}; 'cc'}}; {'aa2' {'dd'; 'ee'}}};
>> recCat(theCellArray)
ans =
'aa1.bb.b1.b11.b12.b2'
'aa1.cc'
'aa2.dd'
'aa2.ee'
However, you probably meant b11 and b12 to be on the same column not row so in that case:
>> theCellArray = {{'aa1' {{'bb' {'b1' {'b11';'b12'} 'b2'}}; 'cc'}}; {'aa2' {'dd'; 'ee'}}};
>> recCat(theCellArray)
ans =
'aa1.bb.b1.b11.b2'
'aa1.bb.b1.b12.b2'
'aa1.cc'
'aa2.dd'
'aa2.ee'

Here's a sweet one:
out = cellfun(#(y) cellfun(#(x) [ y{1} '.' x],y{2},'UniformOutput',false),theCellArray,'UniformOutput',false)
out{:}
ans =
'aa1.bb'
'aa1.cc'
ans =
'aa2.dd'
'aa2.ee'
Super One liner! (but not very efficient) And only works with original pose of question with 2 levels of cell strings.

Related

Storing numpy.ndarrays from a loop

I am trying to store the numpy.ndarrays defined as x_c, y_c, and z_c for every iteration of the loop:
for z_value in np.arange(0, 5, 1):
ms.set_current_mesh(0)
planeoffset : float = z_value
ms.compute_planar_section(planeaxis = 'Z Axis', planeoffset = planeoffset)
m = ms.current_mesh()
matrix_name = m.vertex_matrix()
x_c = matrix_name[:,0]
y_c = matrix_name[:,1]
z_c = matrix_name[:,2]
I would like to be able to recall the three arrays at any z_value, preferably with reference to the z_value i.e x_c # z_value = 2 or similar.
Thanks for any help!
p.s very new to coding, so please go easy on me.
You have to store each array in an external variable, for example a dictionary
x_c={}
y_c={}
z_c={}
for z_value in np.arange(0, 5, 1):
ms.set_current_mesh(0)
planeoffset = float(z_value)
ms.compute_planar_section(planeaxis = 'Z Axis', planeoffset = planeoffset)
m = ms.current_mesh()
m.compact()
print(m.vertex_number(), "vertices in Planar Section Z =", planeoffset)
matrix_name = m.vertex_matrix()
x_c[planeoffset] = matrix_name[:,0]
y_c[planeoffset] = matrix_name[:,1]
z_c[planeoffset] = matrix_name[:,2]
Please, ensure you call m.compact() before accessing the vertex_matrix or you will get a MissingCompactnessException error. Please, note that it is not the same to store anything in x_c[2] or in x_c[2.0], so choose if your index has to be integers o floats and keep the same type (in this example, they are floats).
Later, you can recall values like this:
print("X Values with z=2.0")
print(x_c[2.0])

Data arrays must have the same length, and match time discretization in dynamic problems error in GEKKO

I want to find the value of the parameter m that minimizes my variable x subject to a system of differential equations. I have the following code
from gekko import GEKKO
def run_model_m(days, population, case, k_val, b_val, u0_val, sigma_val, Kmax0, a_val, c_val):
list_x =[]
list_u =[]
list_Kmax =[]
for i in range(len(days)):
list_xi=[]
list_ui=[]
list_Ki=[]
for j in range(len(days[i])):
#try:
m = GEKKO(remote=False)
#m.time= days[i][j]
eval = np.linspace(days[i][j][0], days[i][j][-1], 100, endpoint=True)
m.time = eval
x_data= population[i][j]
variable= np.linspace(population[i][j][0], population[i][j][-1], 100, endpoint=True)
x = m.Var(value=population[i][j][0], lb=0)
sigma= m.Param(sigma_val)
d = m.Param(c_val)
k = m.Param(k_val)
b = m.Param(b_val)
r = m.Param(a_val)
step = np.ones(len(eval))
step= 0.2*step
step[0]=1
m_param = m.CV(value=1, lb=0, ub=1, integer=True); m_param.STATUS=1
u = m.Var(value=u0_val, lb=0, ub=1)
#m.free(u)
a = m.Param(a_val)
c= m.Param(c_val)
Kmax= m.Param(Kmax0)
if case == 'case0':
m.Equations([x.dt()== x*(r*(1-x/(Kmax))-m_param/(k+b*u)-d), u.dt()== sigma*(m_param*b/((k+b*u)**2))])
elif case == 'case4':
m.Equations([x.dt()== x*(r*(1-u**2)*(1-x/(Kmax))-m_param/(k+b*u)-d), u.dt() == sigma*(-2*u*r*(1-x/(Kmax))+(b*m_param)/(b*u+k)**2)])
p = np.zeros(len(eval))
p[-1] = 1.0
final = m.Param(value=p)
m.Obj(x)
m.options.IMODE = 6
m.options.MAX_ITER=15000
m.options.SOLVER=1
# optimize
m.solve(disp=False, GUI=False)
#m.open_folder(dataset_path+'inf')
list_xi.append(x.value)
list_ui.append(u.value)
list_Ki.append(m_param.value)
list_x.append(list_xi)
list_Kmax.append(list_Ki)
list_u.append(list_ui)
return list_x, list_u, list_Kmax, m.options.OBJFCNVAL
scaled_days[i][j] =[-7.0, 42.0, 83.0, 125.0, 167.0, 217.0, 258.0, 300.0, 342.0]
scaled_pop[i][j] = [0.01762491277346285, 0.020592540360308997, 0.017870838266697213, 0.01690069378982034,0.015512320147187675,0.01506701796298272,0.014096420738841563,0.013991224004743027,0.010543380664478205]
k0,b0,group, case0, u0, sigma0, K0, a0, c0 = (100, 20, 'Size3, Inc', 'case0', 0.1, 0.05, 2, 0, 0.01)
list_x2, list_u2, list_Kmax2,final =run_model_m(days=[[scaled_days[i][j]]], population=
[[scaled_pop[i][j]]],case=case1, k_val=list_b1[i0][0], b_val=b1, u0_val=list_u1[i0][j0],
sigma_val=sigma1, Kmax0=K1, a_val=list_Kmax1[0][0], c_val=c1)
I get the error Data arrays must have the same length, and match time discretization in dynamic problems error but I don't understand why. I have tried making x and m_param arrays, with x=m.Var, m_param =m.MV... But still get the same error, even if they are all arrays of the same length. Is this the right way to find the solution of the minimization problem?
I think the error was just that in run_model_m I was passing a list as u0_val and it didn't have the same dimensions as m.time. So it should be u0_val=list_u1[0][0][0]

Create array of "deep" struct (scalar) fields

How can I collapse the values of "deep" struct fields into arrays by just indexing?
In the example below, I can only do it for the "top-most" level, and for "deeper" levels I get the error:
"Expected one output from a curly brace or dot indexing expression, but there were XXX results."
The only workaround I found so far is to unfold the operation into several steps, but the deeper the structure the uglier this gets...
clc; clear variables;
% Dummy data
my_struc.points(1).fieldA = 100;
my_struc.points(2).fieldA = 200;
my_struc.points(3).fieldA = 300;
my_struc.points(1).fieldB.subfieldM = 10;
my_struc.points(2).fieldB.subfieldM = 20;
my_struc.points(3).fieldB.subfieldM = 30;
my_struc.points(1).fieldC.subfieldN.subsubfieldZ = 1;
my_struc.points(2).fieldC.subfieldN.subsubfieldZ = 2;
my_struc.points(3).fieldC.subfieldN.subsubfieldZ = 3;
my_struc.info = 'Note my_struc has other fields besides "points"';
% Get all fieldA values by just indexing (this works):
all_fieldA_values = [my_struc.points(:).fieldA]
% Get all subfieldM values by just indexing (doesn't work):
% all_subfieldM_values = [my_struc.points(:).fieldB.subfieldM]
% Ugly workaround:
temp_array_of_structs = [my_struc.points(:).fieldB];
all_subfieldM_values = [temp_array_of_structs.subfieldM]
% Get all subsubfieldZ values by just indexing (doesn't work):
% all_subsubfieldZ_values = [my_struc.points(:).fieldC.subfieldN.subsubfieldZ]
% Ugly workaround:
temp_array_of_structs1 = [my_struc.points(:).fieldC];
temp_array_of_structs2 = [temp_array_of_structs1.subfieldN];
all_subsubfieldZ_values = [temp_array_of_structs2.subsubfieldZ]
Output:
all_fieldA_values =
100 200 300
all_subfieldM_values =
10 20 30
all_subsubfieldZ_values =
1 2 3
Thanks for any help!
You can use arrayfun to have acces to each individual 'point', and then acces its data. This will return an array with the same dimensions as my_struc.points:
all_subfieldM_values = arrayfun(#(in) in.fieldB.subfieldM, my_struc.points)
all_subsubfieldZ_values = arrayfun(#(in) in.fieldC.subfieldN.subsubfieldZ, my_struc.points)
Not optimal, but at least it's one line.

Methods from Class Arrays

I have several classes with a lot of methods and functions, which normally handles mx1 arrays. For a given class:
S1.x=randn(m,1);
S1+2*randn(m,1); % Plus Override
S1.smooth; % Class Methods
S1.detrend;
Now i wish to handle class arrays for the same given class, on a way like this;
S=[S1 S2 S3 S4];
S.smooth; % Methods for Class Array
S.detrend;
Question:
Is there a simple way for doing this, without rewritting all the functions implementing the class properties and methods?
I am looking for some specific addition, redefinition, piece of code, trick, etc. in order to do that in a clean way. The purpose of this is code functionality, not performance -the few performance critical functions are already vectorized-.
Greetings,
How about that:
classdef TestClass
methods
function smooth(obj)
if numel(obj) == 1
disp('Hello')
else
for i=1:numel(obj)
obj(i).smooth;
end
end
end
end
end
Called as follow:
>> t1 = TestClass;
>> t1.smooth
Hello
>> t2 = [TestClass TestClass TestClass];
>> t2.smooth
Hello
Hello
Hello
If you really wanted to you should also be able to overload the subsref operator to automatically do that on all your methods (it gives you access to the . operator) . However in my experience overloading subsref correctly is not straight forward and might be more effort than what is worth.
Here is an example of this idea. It's simplistic and you will likely will need further refinement on your part but should get you started. Note the cheer amount of hackery :)
classdef TestClass
properties
Value
end
methods
function obj = TestClass(x)
obj.Value = x;
end
function smooth(obj)
fprintf('I am %d\n', obj.Value)
end
function res = opposite(obj)
res = -obj.Value;
end
function [res1,res2,res3] = test(obj)
res1 = obj.Value;
res2 = res1*res1;
res3 = res2*res1;
end
function varargout = subsref(A,S)
if numel(A) > 1 && strcmp(S(1).type, '.')
if nargout == 0
feval(S.subs, A(1));
else
nout = nargout(['TestClass>TestClass.' S.subs]);
if nout < 0
nout = -nout;
end
if nout == 0
arrayfun(#(x)feval(S.subs, x), A);
varargout = cell(1, nargout);
else
for i=1:nargout
[output{1:nout}] = feval(S.subs, A(i));
varargout{i} = output;
output = {};
end
end
end
else
if nargout == 0
builtin('subsref', A, S);
else
varargout{:} = builtin('subsref', A, S);
end
end
end
end
Example of use:
>> t1 = TestClass(5);
>> t1.smooth;
I am 5
>> t2 = [TestClass(1) TestClass(2) TestClass(3)];
>> t2(2).smooth;
I am 2
>> t2.smooth;
I am 1
I am 2
I am 3
>> t2(1:2).smooth
I am 1
I am 2
>> t2(2:3).smooth
I am 2
I am 3
>> t2([1 3]).smooth
I am 1
I am 3
>> t2.test
ans =
[1] [1] [1]
ans =
[2] [4] [8]
ans =
[3] [9] [27]

Using two array's in one application with progressing the arrays

I have the below code I'm trying to put together and I'm running into a Run-time error '9' subscript out of range. This does work through the first run through then errors. I don't see why it won't allow for the string to go forward. From what I'm reading it should go through the application changing the X values with Y value 1 and when completed with that set to go to the next Y and start the whole process again until the end of Y. Any help would be appreciated.
Dim Cat(1 To 10) As String
Cat(1) = "010" 'SD
Cat(2) = "020" 'FD
Cat(3) = "050" 'WVID
Cat(4) = "040" 'VID
Cat(5) = "030" 'MEM
Cat(6) = "080" 'ACC
Cat(7) = "060" 'HDMI
Cat(8) = "070" 'SSD
Cat(9) = "090" 'POWER
Cat(10) = "990" 'ZRM
Dim Month(1 To 12) As String
Month(1) = "January"
Month(2) = "February"
Month(3) = "March"
Month(4) = "April"
Month(5) = "May"
Month(6) = "June"
Month(7) = "July"
Month(8) = "August"
Month(9) = "September"
Month(10) = "October"
Month(11) = "November"
Month(12) = "December"
For Y = 1 To UBound(Cat)
For X = 1 To UBound(Month)
Month(X) = Application.WorksheetFunction.SumIf(Sheets(Month(X)).Columns("AO"), Cat(Y), Sheets(Month(X)).Columns("AG"))
Next X
Cells(3 + Y, 41).Value = Application.WorksheetFunction.Sum(Month(1), Month(2), Month(3), Month(4), Month(5), Month(6), Month(7), Month(8), Month(9), Month(10), Month(11), Month(12))
Next Y
End Sub
On the first run through the loop indexed by X you are computing a conditional sum of data stored in Sheet "January". And then overwriting "January" with that value in Month(X). Let's say that that value is 42. On your next run through the loop 42 is in Month(X) so you are looking for Sheets(42), which probably isn't a valid worksheet. I would try this instead.
dim temp as double
For Y = 1 To UBound(Cat)
temp = 0# '0 as a double.
For X = 1 To UBound(Month)
temp = temp + Application.WorksheetFunction.SumIf(Sheets(Month(X)).Columns("AO"), Cat(Y), Sheets(Month(X)).Columns("AG"))
Next X
Cells(3 + Y, 41).Value = temp
Next Y
This way we don't need to store all of the sums from each sheet, since we only use them to add them all together.

Resources