Is it possible to define multiple enumerations in a single Matlab file? Or is it possible to have "local" enums in the same way we can define local funtions at the end of a file?
I am working on a project where it would be handy to have multiple enumeration classes, but it is annoying to use a classdef every time because it requires a separate file, and this means that there are lots of short files whose sole purpose it is to define enumerations. At the moment, each enumeration looks like this:
classdef exampleEnumType < uint32
enumeration
zero(0),
one(1),
two(2),
end
end
Is there a way to compactly define enumerations in Matlab so that I do not need a separate file for each (using Matlab 2021a)?
First of all, having lots of short files is the normal situation in MATLAB. Working around that is possible but oftentimes futile.
Traditionally in MATLAB, constant values are defined as a function. For example, pi is a function. It looks something like this:
function v = pi
v = 3.14159
By making the constant into a function, it is available from everywhere without first running code to define those constants.
An enumeration is nothing more than a series of constants. The same can be accomplished with a struct:
exampleEnumType = struct('zero',0, 'one',1, 'two',2);
Since fairly recently (R2019b), MATLAB allows dot indexing into the output of a function call, but you do need to use empty parenthesis in the function call. Thus, we can declare the above struct the same way we did with constants:
function v = exampleEnumType
v = struct('zero',0, 'one',1, 'two',2);
This allows to do exampleEnumType().zero (almost) like with the enum or with a struct variable.
So how do we extend this to defining multiple of these in a single file? If a common prefix is no problem, we can define a class with static member functions, each one declaring a constant:
classdef constants
methods(Static)
function v = pi
v = 3.14159
end
function v = exampleEnumType
v = struct('zero',0, 'one',1, 'two',2);
end
end
end
We now have constants.pi and constants.exampleEnumType().zero.
Alternatively, create a single function that returns a more complex struct as follows:
function v = constants
v.pi = 3.14159;
v.exampleEnumType = struct('zero',0, 'one',1, 'two',2);
This allows us to do constants().exampleEnumType.zero.
Note that the above will not work in the same way for MATLAB releases prior to R2019b. For older versions of MATLAB, the last method (a function constants) would be the best approach. The user would just need to do constants = constants; at the top of any function needing to use the constants. This shadows the function with a variable of the same name, so that constants.exampleEnumType.zero works as expected.
You can use a map...
exampleEnum = containers.Map( {'zero','one','two'}, {0,1,2} );
usage looks like
exampleEnum('zero') % = 0
I'm thinking you might want to use categorical arrays here, and stick "enumerations" of their valid values as constants in a common class.
classdef Constants
properties (Constant)
Foods = categorical(["apple", "banana", "pear"])
SupportedProtocols = categorical("http", "https", "ftp")
SpeedOfGravityMps = 9.86
end
end
If you want them to be true Matlab enumerations, then yeah, you're stuck with a separate file for each.
Related
I am looking for a way to compare finite sequential data with non-deterministic ordering in MATLAB. Basically, what I want is an array, but without imposing an order on the contained elements. If I have the objects
a = [x y z];
and
b = [x z y];
I'd want isequal(a, b) to return true. With arrays, this is not the case. The easy fix would be to sort the entries before comparing them. Unfortunately, in my case the elements are complex objects which cannot easily be mapped to have an unambigious numerical relationship to each other. Another approach would be not to use isequal, but rather a custom comparison function which asserts matching lengths and then simply checks if each element from the first array is contained in the second one. However, in my case the arrays are non-trivially nested inside the structs I am trying to compare via isequal, and it would be quite complicated to write a custom comparison function for the encapsulating structs. Other than this ordering problem, the inbuilt isequal function covers all of my needs, as it correctly handles arbitrarily nested structs with arbitrary fields, so I would really like to avoid writing a complicated custom function for that.
Is there any datatype in MATLAB which allows for the described behavior? Or is there a way to easily build such a custom type? In Java, I could simply write a wrapper class with a custom implementation for the equals method, but there seems to be no such mechanism in MATLAB?
I've found a way to solve my problem elegantly. Contrary to my previously stated belief, MATLAB actually does allow for class-specific overriding of isequal.
classdef CustomType
properties
value
end
methods
function self = CustomType(value)
self.value = value;
end
function equal = isequal(self, other)
if not(isa(other, 'CustomType'))
equal = false;
return;
end
% implement custom comparison rules here
end
end
end
So, I can simply assign the fields in question like this and don't have to change anything else in my code:
a = Set([x y z]); % custom type
...
b = Set([x z y]);
...
isequal(a, b); % true
In my use case, I don't even need the uniqueness property of sets. So I only have to perform order-independent comparison and don't need to waste performance on ensuring unrequired properties. Furthermore, by using a dedicated type, I can differentiate explicitly between fields which have order (i.e. regular arrays) and those which don't, at the moment of assignment.
Another solution might be to overwrite the inbuilt isequal and make it apply custom comparison rules when its arguments are of specific type. However, this would slow down all comparisons in the whole program and make for bad encapsulation. I feel like using a custom type with an overriden isequal is the way to solve this kind of problem. But I still think that sets (and other types of commonly used containers) should be included in the basic repertoire of MATLAB.
I was having a doubt today :).
For
A=1;
is there any function f that does the same? like following
f(A,1);
It could help me in some cases like in cellfun or something like that.
You can do this easily if your variable A is a handle class object, thus giving it reference behavior. You could then create a method f for the class that accepts a class object A and a new value for it to store. See Object-Oriented Programming for more information.
For data types like double or cell there are no built-in functions that work this way. You could make your own function using assignin and inputname like so:
function f(var, value)
assignin('caller', inputname(1), value);
end
And call it as follows, with A already defined:
A = 0;
f(A, 1); % Changes the value of A to 1
However, this would generally be considered bad practice as it makes the code harder to follow, as call-by-value behavior is the expected norm.
In general no, MATLAB functions cannot change their input.
But, if you are brave, you can create a MEX-file that breaks that promise and does change the input. In a MEX-file you can write to the input array, but doing so carelessly causes havoc. For example,
B = A;
f(A,1); % <- modifies A
would cause B to also be modified, because MATLAB delays copying the data when you do B = A. That is, the two variables point to the same data until you modify one, at which point the data is copied. But in a MEX-file you can write to a matrix without doing this check, thereby modifying B also. The link I provided shows how to modify A carefully.
What benefit does it get from treating functions specially? For example,
function n = f(x)
2*x
endfunction
f(2) //outputs 4
f = #f
f(2) //outputs 4
If handles can be called the same way as functions, then what benefit do we get from functions being treated specially. By specially I mean that variables referring to functions can't be passed as arguments:
function n = m(f,x)
f(x)
end
m(f,2) // generates error since f is called without arguments
Why aren't functions procedures (which are always pointed to by variables) like in other functional languages?
EDIT:
It seems like my question has been completely misunderstood, so I will rephrase it. Compare the following python code
def f(x):
return 2*x
def m(f,x):
return f(x)
m(f,3)
to the octave code
function n = f(x)
2*x
end
function n = m(f,x)
f(x)
end
m(#f,2) % note that we need the #
So my question then is, what exactly is a function "object" in octave? In python, it is simply a value (functions are primitive objects which can be assigned to variables). What benefit does octave/matlab get from treating functions differently from primitive objects like all other functional languages do?
What would the following variables point to (what does the internal structure look like?)
x = 2
function n = f(x)
2*x
end
g = #f
In python, you could simply assign g=f (without needing an indirection with #). Why does octave not also work this way? What do they get from treating functions specially (and not like a primitive value)?
Variables referring to functions can be passed as arguments in matlab. Create a file called func.m with the following code
function [ sqr ] = func( x )
sqr = x.^2;
end
Create a file called 'test.m' like this
function [ output ] = test( f, x )
output = f(x);
end
Now, try the following
f=#func;
output = test(f, 3);
There's no "why is it different". It's a design decision. That's just how matlab/octave works. Which is very similar to how, say, c works.
I do not have intricate knowledge of the inner workings of either, but presumably a function simply becomes a symbol which can be accessed at runtime and used to call the instructions specified in its definition (which could be either interpreted or precompiled instructions). A "function handle" on the other hand, is more comparable to a function pointer, which, just like c, can either be used to redirect to the function it's pointing to, or passed as an argument.
This allows matlab/octave to do stuff like define a function completely in its own file, and not require that file to be run / imported for the function to be loaded into memory. It just needs to be accessible (i.e. in the path), and when matlab/octave starts a new session, it will create the appropriate table of available functions / symbols that can be used in the session. Whereas with python, when you define a function in a file, you need to 'run' / import that file for the function definition to be loaded into memory, as a series of interpreted instructions in the REPL session itself. It's just a different way of doing things, and one isn't necessarily better than the other. They're just different design / implementation decisions. Both work very well.
As for whether matlab/octave is good for functional programming / designed with functional programming in mind, I would say that it would not be my language of choice for functional programming; you can do some interesting functional programming with it, but it was not the kind of programming that it was designed for; it was primarily designed with scientific programming in mind, and it excels at that.
I am writing some Matlab code that I am parsing into c++. The C++ Looks like this:
ICOMPL[dataPath].Value =5;
How to write this in Matlab so that the syntax is similar? For example;
ICOMPL = [0,1,2,3];
Let's me do
ICOMPL(datapath+1) = 5;
But how to add the value part? I would need that each element in the array would have the name value.
Note that MATLAB is not C++ so not everything has to be the same, specially when you get to objects. My answer assumes that ICOMPL is not an object from a class, but an struct:
You can make structs in MATLAB, also arrays of structs.
A struct is as easy as
ICOMPL.Value= 5;
An array of structs:
ICOMPL(datapath+1).Value = 5;
So each of ICOMPL will be a whole struct. Note that you may not need this, and you may want to have
ICOMPL.Value= 1:5;
A single struct with several values on each of its elements. Often this last one is easier to work with in MATLAB. That's your decision to make.
when I am doing a function in Matlab. Sometimes I have equations and every one of these have constants. Then, I have to declare these constants inside my function. I wonder if there is a way to call the values of that constants from outside of the function, if I have their values on the workspace.
I don't want to write this values as inputs of my function in the function declaration.
In addition to the solutions provided by Iterator, which are all great, I think you have some other options.
First of all, I would like to warn you about global variables (as Iterator also did): these introduce hidden dependencies and make it much more cumbersome to reuse and debug your code. If your only concern is ease of use when calling the functions, I would suggest you pass along a struct containing those constants. That has the advantage that you can easily save those constants together. Unless you know what you're doing, do yourself a favor and stay away from global variables (and functions such as eval, evalin and assignin).
Next to global, evalin and passing structs, there is another mechanism for global state: preferences. These are to be used when it concerns a nearly immutable setting of your code. These are unfit for passing around actual raw data.
If all you want is a more or less clean syntax for calling a certain function, this can be achieved in a few different ways:
You could use a variable number of parameters. This is the best option when your constants have a default value. I will explain by means of an example, e.g. a regular sine wave y = A*sin(2*pi*t/T) (A is the amplitude, T the period). In MATLAB one would implement this as:
function y = sinewave(t,A,T)
y = A*sin(2*pi*t/T);
When calling this function, we need to provide all parameters. If we extend this function to something like the following, we can omit the A and T parameters:
function y = sinewave(t,A,T)
if nargin < 3
T = 1; % default period is 1
if nargin < 2
A = 1; % default amplitude 1
end
end
y = A*sin(2*pi*t/T);
This uses the construct nargin, if you want to know more, it is worthwhile to consult the MATLAB help for nargin, varargin, varargout and nargout. However, do note that you have to provide a value for A when you want to provide the value of T. There is a more convenient way to get even better behavior:
function y = sinewave(t,A,T)
if ~exists('T','var') || isempty(T)
T = 1; % default period is 1
end
if ~exists('A','var') || isempty(A)
A = 1; % default amplitude 1
end
y = A*sin(2*pi*t/T);
This has the benefits that it is more clear what is happening and you could omit A but still specify T (the same can be done for the previous example, but that gets complicated quite easily when you have a lot of parameters). You can do such things by calling sinewave(1:10,[],4) where A will retain it's default value. If an empty input should be valid, you should use another invalid input (e.g. NaN, inf or a negative value for a parameter that is known to be positive, ...).
Using the function above, all the following calls are equivalent:
t = rand(1,10);
y1 = sinewave(t,1,1);
y2 = sinewave(t,1);
y3 = sinewave(t);
If the parameters don't have default values, you could wrap the function into a function handle which fills in those parameters. This is something you might need to do when you are using some toolboxes that impose constraints onto the functions that are to be used. This is the case in the Optimization Toolbox.
I will consider the sinewave function again, but this time I use the first definition (i.e. without a variable number of parameters). Then you could work with a function handle:
f = #(x)(sinewave(x,1,1));
You can work with f as you would with an other function:
e.g. f(10) will evaluate sinewave(10,1,1).
That way you can write a general function (i.e. sinewave that is as general and simple as possible) but you create a function (handle) on the fly with the constants substituted. This allows you to work with that function, but also prevents global storage of data.
You can of course combine different solutions: e.g. create function handle to a function with a variable number of parameters that sets a certain global variable.
The easiest way to address this is via global variable:
http://www.mathworks.com/help/techdoc/ref/global.html
You can also get the values in other workspaces, including the base or parent workspace, but this is ill-advised, as you do not necessarily know what wraps a given function.
If you want to go that route, take a look at the evalin function:
http://www.mathworks.com/help/techdoc/ref/evalin.html
Still, the standard method is to pass all of the variables you need. You can put these into a struct, if you wish, and only pass the one struct.