Define Matlab Class with Attributes of Another Class - matlab

I'm trying to construct a class framework for a neural network (ANN) in Matlab by defining a Node class:
function NodeObject = Node(Input, Weights, Activation)
Features.Input = [];
Features.Weights = [];
Features.Activation = [];
Features.Input = Input;
Features.Weights = Weights;
Features.Activation = Activation;
NodeObject = class(Features, 'Node');
Where here the input is an integer (expected number of inputs), Weights is a vector of length Features.Input, and Features.Activation is a string that references an activation function stored in the methods.
What I want to do next is construct a cell array of nodes and define a Network class based on this array:
function Architecture = Network(NodeArray)
ANN.Layers = []; % Number of layers in architecture
ANN.LayerWidths = []; % Vector of length ANN.Layers containing width of each layer
ANN.NodeArray = []; % Original input is cell array with layers in ascending order (input at top, output at bottom) with nodes in each row.
ANN.InputSizes = [];
% Find number of layers
ANN.Layers = length(NodeArray(:,1));
% Find width of each layer
Widths = zeros(ANN.Layers,1);
for i = 1:length(Widths)
Widths(i) = length(NodeArray(:,i));
end
ANN.LayerWidths = Widths;
% Pass NodeArray to Network class
ANN.NodeArray = NodeArray;
% Construct cell of input sizes
InputSizes = [];
for i = 1:ANN.Layers
for j = 1:Widths(i)
InputSizes(i,j) = NodeArray{i,j}.Inputs;
end
end
ANN.InputSizes = InputSizes;
Architecture = class(ANN, 'Network');
The attribute ANN.InputSizes tries to extract the attributes from a Node object, but my code doesn't allow me to do this. How do I amend this problem, or do you recommend a different architecture to this problem all together? Currently my classes Node and Network are contained in two separate directories, but I have a feeling that there is something else I'm not seeing. For reference, I have absolutely no prior experience in OOP, and from what I've gathered it seems Matlab is not the best environment in which to implement these structures. At the moment though I don't have enough experience to implement this type of framework in another language.

Your InputSizes isn't a cell. You initialize it to a double array ([]) and then fill it as such. If you want to define it as a cell you should do something like
InputSizes = cell();
for i = 1:ANN.Layers
for j = 1:Widths(i)
InputSizes{i,j} = NodeArray{i,j}.Inputs;
end
end
All of that, you should really look into defining your classes using a classdef file, as it is much more straightforward.
Node.m
classdef Node < handle
properties
Inputs
Weights
Activation
end
methods
function obj = Node(inputs, weights, activation)
obj.Inputs = inputs;
obj.Weights = weights;
obj.Activation = activation;
end
end
end
Network.m
classdef Network < handle
properties
NodeArray
end
properties (Dependent)
Layers
LayerWidths
InputSizes
end
methods
function obj = Network(nodes)
obj.NodeArray = nodes;
end
function result = get.Layers(obj)
result = size(obj.NodeArray, 1);
end
function result = get.LayerWidths(obj)
result = size(obj.NodeArray, 2);
end
function result = get.InputSizes(obj)
result = arrayfun(#(x)x.Inputs, obj.NodeArray, 'uniformoutput', 0);
end
end
end
As far as suggesting a better layout, that's subject to the opinion of the individual developer.

Related

UI in Matlab to get inputs to be used in a script

I am trying to create a GUI for my script in Matlab. At the moment I am opening this dialog boxes in my script to get the inputs I need.
prompt = {'Mass [kg]:','Power [kW]:','Drag Coeff:','Lift Coeff:','Area Front [m^2]:'};
dlgtitle = 'Vehicle Parameters';
dims = [1 35];
definput = {'752','650','1','3','1'};
vehicle = inputdlg(prompt,dlgtitle,dims,definput);
prompt = {'Friction Coeff:','Air Density [kg/m^3]:'};
dlgtitle = 'External Parameters';
dims = [1 35];
definput = {'1.4','1.19'};
ambient = inputdlg(prompt,dlgtitle,dims,definput);
prompt = {'Length [m]:','Corner Radius [m]:'};
dlgtitle = 'Track Parameters';
dims = [1 35];
definput = {'1000','150'};
track = inputdlg(prompt,dlgtitle,dims,definput);
Here the code continues
laptime = formula used to get the laptime;
However I would like to create something similar to what this image shows, where I can write the parameters, push the run button to run the script and get the laptime printed. Any suggestions on how I could achieve it?
Thanks a lot in advance!
steeven:
From inspecting your image, you essentially will need:
A figure object.
Ten(10) field objects.
Ten(10) Static text objects.
A pushbutton object
A callback function.
Here's a sample script:
clc
clear
close all %Very important when making GUI's in MATLAB!
%figure object that contains GUI.
f = figure('units','normalized');
%Uicontrols devoted to static text:
m_text = uicontrol('Parent',f,'units','normalized','Style','Text');
P_text = uicontrol('Parent',f,'units','normalized','Style','Text');
FS_text = uicontrol('Parent',f,'units','normalized','Style','Text');
CD_text = uicontrol('Parent',f,'units','normalized','Style','Text');
CL_text = uicontrol('Parent',f,'units','normalized','Style','Text');
CF_text = uicontrol('Parent',f,'units','normalized','Style','Text');
rho_text = uicontrol('Parent',f,'units','normalized','Style','Text');
len_text = uicontrol('Parent',f,'units','normalized','Style','Text');
rad_text = uicontrol('Parent',f,'units','normalized','Style','Text');
%Uicontrols devoted to editable fields:
m_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
P_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
FS_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
CD_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
CL_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
CF_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
rho_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
len_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
rad_edit = uicontrol('Parent',f,'units','normalized','Style','edit');
% MLG Cell array strat.
ui_texts = {m_text,P_text,FS_text,CD_text,CL_text,CF_text,rho_text,...
len_text,rad_text};
strings = {'mass','power','Front Section','Drag Coefficient',...
'Lift Coefficient','Friction Coefficient','Air Density','Length',...
'Radius'};
ui_edits = {m_edit,P_edit,FS_edit,CD_edit,CL_edit,CF_edit,rho_edit,...
len_edit,rad_edit};
defaults = {'10','100','0.5','0.05','1.2','0.0005','1.225','5','3'};
xi = 0.05; %X-coordinate of Bottom-Left corner.
yi = 0.85; %Y-coordinate of Bottom-Left corner.
width = 0.15; %Width of object.
height = 0.075; %Height of object
deltaH = 0.3; %Horizontal Spacing between objects.
deltaV = -0.25; %Vertical Spacing between objects.
offset = 0.15;
rows = 3; %Number of rows.
cols = 3; %Number of columns.
k = 0; % Counter for number of uicontrols that populate grid pattern.
for i = 1:rows
for j = 1:cols
k = k + 1;
if k <= length(ui_texts)
x = xi + deltaH*(j-1);
y = yi + deltaV*(i-1);
xo = x + offset; %horizontally offset the editable field.
set(ui_texts{k},'Position',[x, y, width, height],'String',strings{k})
set(ui_edits{k},'Position',[xo, y, width, height],'String',defaults{k})
end
end
end
%Uicontrol for output object:
out = uicontrol('Parent',f,'Style','text','units','normalized',...
'position',[xo-deltaH,y+deltaV,width,height],'String','Val = ');
%Uicontrol for button execution:
exe = uicontrol('Parent',f,'Style','pushbutton','units','normalized',...
'position',[xo-2*deltaH,y+deltaV,width,height],'String','Calculate',...
'Callback',{#computations,ui_edits,out});
%Function executed by the "exe" uicontrol.
function computations(obj,~,ui_edits,out)
no_inputs = length(ui_edits);
summation = 0;
for i = 1:no_inputs
in = get(ui_edits{i},'String');
val = str2double(in);
summation = summation +val;
end
set(out,'String',['Val = ',num2str(summation)])
end
The above script produces:
Here's the gist:
The figure is a graphical object needed to contain the editable fields and text descriptions.
The fields are objects that enable user input (These are uicontrol objects).
The static texts establish to the user the correspondence between field and input (These are also uicontrol objects).
The button is an object that executes the callback function (also a uicontrol).
The callback function is a user-defined function that collects inputs from uicontrol objects and uses them to run code.
In this example, the "calculate" button simply sums up all the numeric values of the inputs. For your applications, you must modify the programmer-defined function at the end to suit your needs.
This kind of GUI lets users input information as strings. Said information must be converted from the string type to the double type. Other GUI objects allow for direct numerical inputs (such as sliders or buttons with underlying logical structure, ie. "if this button, then this value"). When working with editable fields, the programmer must be conscious that the inputs are strings until run through a function like str2double.
Other nuances with GUI's:
Every object that the programmer intends to be interactive must have an associated programmer-defined function.
In this case, the only interactive object is the button.
Personally, my biggest challenge when making MATLAB GUI's is dealing with the positioning of the UI controls. I have used a few for loops and cell arrays to generate the grid pattern for the texts and buttons. This is quality of life on my part, more elaborate GUI's may require more sophisticated coding.
MATLAB has a feature called "GUIDE" which helps automate the uicontrol generation. This is worth a try if the programatic method I have shared is too tedious.

Can I code a deep learning layer without a backward function?

I want to create a layer that make two copies of the previous layer (input layer), here is my code:
classdef CopyLayer < nnet.layer.Layer
methods
function layer = CopyLayer(numOutputs,name)
% Set number of inputs.
layer.NumOutputs = numOutputs;
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "Make " + numOutputs + ...
" copies of the input layer";
end
function [varargout] = predict(X)
% Layer forward function for prediction goes here.
numOutputs = layer.NumOutputs;
[h,w,c] = size(X);
Z = zeros(h,w,c,numOutputs);
for i= 1 : numOutputs
Z(:,:,:,i) = X;
end
varargout = Z;
end
% function [] = backward()
% end
end
end
and when I try to create the layer by:
layer = CopyLayer(2,'copy');
the following error appears:
Abstract classes cannot be instantiated. Class 'CopyLayer' inherits
abstract methods or properties but does not implement them.
See the list of methods and properties that 'CopyLayer' must implement
if you do not intend the class to be abstract.
Error in SplitLayer (line 1)
layer = CopyLayer(2,'copy');
and I think it's because of the no existing of backward function. Is that correct? How can I resolve this error?
The error message is clear -- if you're used to reading error messages, and you're familiar with abstract classes.
A class is abstract if it contains elements that are not yet defined in a manner one could instantiate. They are intended particularly to be templates that the user can fill out to have the desired implementation details. nn.layer.layer is one such abstract class.
When you instantiate an abstract class, but fail to define every template element, then the result is another abstract class -- just with fewer "template" elements. That is what you've done: CopyLayer does not implement backward, so it's still abstract. When you instantiate with layer = CopyLayer(2,'copy'), you still have open elements, so you cannot make a concrete object from the class. Hence the error message.
You can work around this in a couple of ways:
Implement your own layer class, one that doesn't even mention a back-prop function. You'll have extra connection work to do, since you give up your inheritance from nn.layer.
Implement backward, but leave the body non-functional (empty). This will satisfy the compiler, and give you a very boring (but fast) back-prop stage.
thanks to Mr #Prune
the code after correction becomes as follow:
classdef CopyLayer < nnet.layer.Layer
properties
% (Optional) Layer properties.
NumOutputs
end
methods
function layer = CopyLayer(numOutputs,name)
% Set number of inputs.
layer.NumOutputs = numOutputs;
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "Make " + numOutputs + ...
" copies of the input layer";
end
function varargout = predict(layer,X)
numOutputs = layer.NumOutputs;
[h,w,c] = size(X);
Z = zeros(h,w,c,numOutputs);
for i= 1 : numOutputs
Z(:,:,:,i) = X;
end
varargout = Z;
end
function [dLdX] = backward(~,~,~,~,~)
end
end
end

Passing additional iteration-dependent inputs to ode45

I'm trying to solve differential equation using the ode45 function. Consider the following code,
[t1,X2] = ode45(#(t,x)fun(t,x,C1,C2,C3,C4),t0,X01);
where parameters C1, C2, C3 and C4 are column vectors, which should be available to the function that ode45 is referring to (fun.m). I want the values to change after every iteration, so for example, at the beginning the entry of C1 I want in is C1(1), in the next iteration it's C1(2), etc.
How can I implement that?
You may have noticed that the official docs are not too helpful in this scenario (as they pretty much force you to use global variables - which is doable, but discouraged). Instead, I'll show you how this can be done with classes and function handles. Consider the following:
classdef SimpleQueue < handle
%SIMPLEQUEUE A simple FIFO data structure.
properties (Access = private)
data
position
end
methods (Access = public)
function obj = SimpleQueue(inputData)
%SIMPLEQUEUE Construct an instance of this class
obj.data = inputData;
rewind(obj);
end % constructor
function out = pop(obj, howMany)
%POP return the next howMany elements.
if nargin < 2
howMany = 1; % default amount of values to return
end
finalPosition = obj.position + howMany;
if finalPosition > numel(obj.data)
error('Too many elements requested!');
end
out = obj.data(obj.position + 1 : obj.position + howMany);
obj.position = finalPosition;
end % pop
function [] = rewind(obj)
%REWIND restarts the element tracking
% Subsequent calls to pop() shall return elements from the beginning.
obj.position = 0;
end % rewind
end % methods
end % classdef
How to use this? Simple:
C1q = SimpleQueue(C1);
C2q = SimpleQueue(C2);
C3q = SimpleQueue(C3);
C4q = SimpleQueue(C4);
[t1,X2] = ode45(#(t,x)fun(t,x,#C1q.pop,#C2q.pop,#C3q.pop,#C4q.pop),t0,X01);
As you can see, inside fun we use C1q() instead of C1.

All possible combinations of many parameters MATLAB

I have a list of parameters and I need to evaluate my method over this list. Right now, I am doing it this way
% Parameters
params.corrAs = {'objective', 'constraint'};
params.size = {'small', 'medium', 'large'};
params.density = {'uniform', 'non-uniform'};
params.k = {3,4,5,6};
params.constraintP = {'identity', 'none'};
params.Npoints_perJ = {2, 3};
params.sampling = {'hks', 'fps'};
% Select the current parameter
for corrAs_iter = params.corrAs
for size_iter = params.size
for density_iter = params.density
for k_iter = params.k
for constraintP_iter = params.constraintP
for Npoints_perJ_iter = params.Npoints_perJ
for sampling_iter = params.sampling
currentParam.corrAs = corrAs_iter;
currentParam.size = size_iter;
currentParam.density = density_iter;
currentParam.k = k_iter;
currentParam.constraintP = constraintP_iter;
currentParam.Npoints_perJ = Npoints_perJ_iter;
currentParam.sampling = sampling_iter;
evaluateMethod(currentParam);
end
end
end
end
end
end
end
I know it looks ugly and if I want to add a new type of parameter, I have to write another for loop. Is there any way, I can vectorize this? Or maybe use 2 for loops instead of so many.
I tried the following but, it doesn't result in what I need.
for i = 1:numel(fields)
% if isempty(params.(fields{i}))
param.(fields{i}) = params.(fields{i})(1);
params.(fields{i})(1) = [];
end
What you need is all combinations of your input parameters. Unfortunately, as you add more parameters the storage requirements will grow quickly (and you'll have to use a large indexing matrix).
Instead, here is an idea which uses linear indicies of a (never created) n1*n2*...*nm matrix, where ni is the number of elements in each field, for m fields.
It is flexible enough to cope with any amount of fields being added to params. Not performance tested, although as with any "all combinations" operation you should be wary of the non-linear increase in computation time as you add more fields to params, note prod(sz)!
The code I've shown is fast, but the performance will depend entirely on which operations you do in the loop.
% Add parameters here
params.corrAs = {'objective', 'constraint'};
params.size = {'small', 'medium', 'large'};
params.density = {'uniform', 'non-uniform'};
% Setup
f = fieldnames( params );
nf = numel(f);
sz = NaN( nf, 1 );
% Loop over all parameters to get sizes
for jj = 1:nf
sz(jj) = numel( params.(f{jj}) );
end
% Loop for every combination of parameters
idx = cell(1,nf);
for ii = 1:prod(sz)
% Use ind2sub to switch from a linear index to the combination set
[idx{:}] = ind2sub( sz, ii );
% Create currentParam from the combination indices
currentParam = struct();
for jj = 1:nf
currentParam.(f{jj}) = params.(f{jj}){idx{jj}};
end
% Do something with currentParam here
% ...
end
Asides:
I'm using dynamic field name references for indexing the fields
I'm passing multiple outputs into a cell array from ind2sub, so you can handle a variable number of field names when ind2sub has one output for each dimension (or field in this use-case).
Here is a vectorized solution :
names = fieldnames(params).';
paramGrid = cell(1,numel(names));
cp = struct2cell(params);
[paramGrid{:}] = ndgrid(cp{:});
ng = [names;paramGrid];
st = struct(ng{:});
for param = st(:).'
currentParam = param;
end
Instead of nested loops we can use ndgrid to create the cartesian product of the cell entries so we can find all combinations of cell entries without loop.

How do I iterate through a struct in an Embedded Matlab Function in Simulink?

I have hit a roadblock where I am trying to iterate through a structure formed in the MATLAB workspace inside an EML (Embedded Matlab) function block in SIMULINK. Here is some example code:
% Matlab code to create workspace structure variables
% Create the Elements
MyElements = struct;
MyElements.Element1 = struct;
MyElements.Element1.var1 = 1;
MyElements.Element1.type = 1;
MyElements.Element2 = struct;
MyElements.Element2.var2 = 2;
MyElements.Element2.type = 2;
MyElements.Element3 = struct;
MyElements.Element3.var3 = 3;
MyElements.Element3.type = 3;
% Get the number of root Elements
numElements = length(fieldnames(MyElements));
MyElements is a Bus type Parameter for the MATLAB Function Block (EML) in SIMULINK. Below is the area I am running into trouble with. I know the number of elements inside my struct and I know the names, but the number of elements can change with any configuration. So I cannot hardcode based on the Element names. I have to iterate through the struct inside the EML block.
function output = fcn(MyElements, numElements)
%#codegen
persistent p_Elements;
% Assign the variable and make persistent on first run
if isempty(p_Elements)
p_Elements = MyElements;
end
% Prepare the output to hold the vars found for the number of Elements that exist
output= zeros(numElements,1);
% Go through each Element and get its data
for i=1:numElements
element = p_Elements.['Element' num2str(i)]; % This doesn't work in SIMULINK
if (element.type == 1)
output(i) = element.var1;
else if (element.type == 2)
output(i) = element.var2;
else if (element.type == 3)
output(i) = element.var3;
else
output(i) = -1;
end
end
Any thoughts on how I can iterate through a struct type in SIMULINK? Also, I cannot use any extrinsic functions like num2str because this is to be compiled on a target system.
I believe you are trying to use dynamic field names for structures. The correct syntax should be:
element = p_Elements.( sprintf('Element%d',i) );
type = element.type;
%# ...