Loren on the Art of MATLAB

Best Practices for Programming MATLAB 56

Posted by Loren Shure,

I thought I would share my top goto list of things I try to do when I write MATLAB code. And checking with other MathWorks folks whose code I admire, I found they basically used the same mental list that I use. You can find blog posts on all of these topics by selecting relevant categories from the right side of The Art of MATLAB blog site.

Contents

My List of Best Practices

Clearly (at least to me), this is not everything you generally need to do. You still need to comment the code, add good help information and examples, etc. But these are the main coding practices and tools I always rely on.

  1. Vectorize (but sensibly).
  2. Use bsxfun in lieu of repmat where possible.
  3. When looping through an array, loop down columns to access memory in the same order that MATLAB stores the data in.
  4. Profile the code. I am often surprised about what is taking up the time.
  5. Pay attention to messages from the Code Analyzer.
  6. Use functions instead of scripts.
  7. Don't "poof" variables into any workspaces. Translation, don't use load without a left-hand side; avoid eval, evalin, and assignin.
  8. Use logical indexing instead of find.
  9. Avoid global variables.
  10. Don't use equality checks with floating point values.

Missing from Your List? Additions to My List?

What's on my list that you don't currently do? Do you have a major addition to my list (there can't be too many, or I won't remember to do them all!)? Let me know here.


Get the MATLAB code

Published with MATLAB® 7.13

56 CommentsOldest to Newest

Here’s the biggest thing you missed:

Pay A LOT of attention to code clarity and code design. In 97% of the code you write, tiny improvements in execution speed don’t matter, and yet you (and your colleagues/coworkers) will spend 10-20 times as much time reading your code as you spent typing it.

Having recently moved to a MATLAB environment from other scientific scripting environments, I am stunned by the lackadaisical attitude MATLAB programmers seem to have to code quality from the point of view of legibility and clarity of thought expressed in code through good design. At the same time they frequently reject some well-established software engineering best practices on the grounds that they may cost microseconds in execution time.

The hardware that runs MATLAB now is roughly 100,000 times faster than when MATLAB was first released. Software development practices have changed to recognize the fact that programmer time is vastly more valuable than machine time in almost all cases. MATLAB programmers seem to be behind the curve in realizing this.

JamesL-

I agree with you on writing for clarity, esp. if the speed isn’t horribly impacted. I don’t know a tool to specifically reinforce that though – in looking for specifics, I believe profiling and vectorize sensibly cover the intent of what you are saying, but without the background you provided. Thanks for sharing.

–Loren

Thorough error checking of function input parameters is one of my best practices. By using inputParser and assert(), you can provide future users some guidance at least on the form of variables that are provided as inputs.

This is true throughout the rest of the function as well. I try to explicitly check for as much a priori information as I can. When assertions fail, provide useful information regarding the assumption.

Iain-

Yes, all your items are important for creating robust code. It’s very hard to keep the list small, as you said.

–Loren

Eric-

Yes, error checking is usually important. Interestingly, I have found cases where the error that would occur without checking explicitly was quite clear.

–Loren

instead of doing,

for k=1:N,
array(k)=k;
end

implicitly pre-allocate array by

for k=N:-1:1,
array(k)=k;
end

“Use bsxfun in lieu of repmat where possible. “

This one is new to me, can you explain why, and how it’s used?

I like the pragmatic theme of today’s post, by the way.

Use unit tests (the earlier the better) and use the Profiler to make sure that every line of code gets exercised.

I’m curious why you prefer functions over scripts. I find that scripts allow me to do things that I cannot do in a function such as have access to all the data created within the script once the script has finished executing. With a function, once the function is finished, the data is gone. Sometimes that’s desirable, other times it’s not.

Loren,

thanks for a nice and suitably short list. There were a couple of best practices that I was not aware of:

2) Using bsxfun in stead of repmat. Do you have any example of when bsxfun is better than repmat? What can be gained in terms of processing time / memory usage?

10) Not checking for equality with floating point values. Could you give an example here, too? I may be guilty of doing this quite often, since the default class in Matlab is double (floating-point).

Hi Loren,

Best wishes for 2012! Very interesting post, thank you. A few comments I might add from my own experience..

Additions to Loren’s list:

1) As multi-function projects get larger & more complex, coding standards & best practices must be applied ever more rigorously.

2) When developing class hierarchies : plan on several development generations & much refactoring before stable, high-quality code is achieved.

3) Within all function M-files : use Hungarian Notation prefixes or suffixes to clarify variable types.

4) Always step through newly-written function M-files & visually check values of every single variable, via datatip, command-line, or Variable Editor.

Qualifications to Loren’s list:

7. Don’t “poof” variables into any workspaces. (unless meta-programming is an integral part of your project design; example upon request)

8. Use logical indexing instead of find. (unless you explicitly want to generate a vector of non-zero indexes)

any comments appreciated,
brad

Thanks, Loren! A valuable list which should be considered by all Matlab users and developers. Some additions – there is no reason to keep the list small:

* Documentation is required to make a working function usable.
Inputs, outputs and the applied procedure must be explained.
Because bugs are everywhere changes of the code must be accompanied by a version history. Without documentation it is impossible to reuse code for other projects.

* Create a unit-test function, which compares the output of the function with a set of known answers. Automatic unit-tests are more powerful than manual tests, because they can run reproducible after each bug fix and when a new Matlab release is used.

* Keep it simple stupid.
This is one of the rare cases, where D.E. Knuth and Conan the Barbarian agree.
I’m still amused by this line from SAVEPATH:
mlr_dirs = cellfun(@(x) ismember(1,x),strfind(dirnames,mlroot))
How funny. What about:
mlr_dirs = strncmp(dirnames, mlroot, length(mlroot));

* program time = design time + programming time + debug time + runtime
Pre-mature optimization of speed will have negative effects to the debug time. A bad design increase the programming time due to necessary refactoring. Spending an hour to save a milli-second of runtime matters, if the program runs more than 3.6e6 times.

11 Disable the Code Analyzer. The code analyzer frequently advice’s you to micro optimize your code not considering the impact on the readability. If you don’t disable it your left with the following bad options:
A Do the optimization and make your code less readable for almost no speed improvement.
B Clutter your code with %#ok
C Ignore the message and let the code be cluttered with underlines easily masking more serious errors such as syntax errors.

Two things come to mind:

1. Don’t get too buried in the code to think about the algorithm and how it can be improved. If you don’t step back, it’s all too easy to write things like sqrt(v) < r when v < r.^2 could be a lot faster if v is a big vector.

2. Try to make your code as general and reusable as possible. (Writing functions rather than scripts is an aspect of this.) This may mean splitting up big functions into smaller ones, making sure that all cases are covered, thinking about whether the arguments give the user all the control they might want, and providing good documentation always.

Loren,
in keeping with reply # 1, my main addition would be that LOTS of comments are good. When I come back to see a routine, a year later, even with lots of comments I sometimes wonder what a particular snippet was for.

And altho’ I agree that “poofing” (is that a standard term?) is not good, I do not know for sure how to do the equivalent of putting a left-hand-side in the code or on the command line when I do an “import data,” other than a comment line.

good stuff, all, and thanks
tony

My list is basically the same, except I also add:

Comment! If I vectorize for speed and it makes the code hard to read I often leave the original, non-vectorized code as a comment (highlight, ctrl+r). This gets the best of both worlds. Anyone reading the code then sees what the vectorized version was meant to do and can uncomment the simple code for debugging or whatever purpose. Other than that, spending the time to comment every step or block can save much time later when performing maintenance, even if it is me looking at my own code. Comments are free, be generous with them.

Test! Depending on how critical the code is, I will spend significant time trying to break it by doing dumb things to the code. Passing in the wrong types of variables, or doing things out of the expected order (especially important for GUIs).

Help! Always spend the time to write good, clear help. This helps the user know (remember) what the code does, even if it is me!

Don’t Mask! Pay attention when assigning variable (and function M-file) names such that built-in functions are not overwritten.

Thanks for all the great feedback. I will only address a few items, at least right now.

1) why a short list? because people need it in their heads, I believe. I don’t think most people have incorporated consulting long lists as part of most of their processes.

2) for bsxfun, please see posts in the vectorization category. At least 2 talk about bsfux.

3) similar to #2, please see the category about numerical accuracy for the issues relating to comparing floating point numbers.

4) functions generally execute more quickly than scripts because they have a contained, known workspace and can be more fully analyzed by the language machinery.

Thanks again!
–Loren

Loren-

Thanks for the thoughtful list. A blog that triggers 17 (and counting) responses is on target.

Your list concentrates on coding practices (8 of 10 items). Many of the responses suggest development practices (test, document, etc). My experience in interacting with over 100 MATLAB users a year is that they are interested in and benefit from both.

Of course you know where my favorite list is…

-Richard

This comment is not exactly “code performance” related, but the importance of clearly named variables/functions should not be overlooked. In my code I try to prefix variable names in a way that makes it immediately obvious what the variable contains. Here are some examples:

(1) Use an “n” or “m” in front of a variable name that stores the number of “things”:
i.e. nRecords = length(recordData);
[nRows,nCols] = size(dataArray);

(2) Use an “i” (or “j” or “k”) in front of a variable name that is incremented in a for-loop to make it clear what the loop is indexing through:
i.e. for iRecord = 1:nRecords
recordData{iRecord} = …;
end

(3) Use “is” as a prefix for logical arrays:
i.e. isDetected = measurementData > threshold;
isInPolygon = inpolygon(x,y,xv,yv);

(4) Use “h” in front of variables that contain handles:
i.e. hAx = axes;
hFig = get(hAx,’Parent’);

Also, it is extremely useful to attach unit identifiers to variable names to avoid (potentially disastrous amounts of) confusion. I like to use an underscore to separate the variable name from the units for clarity:
i.e. elevationAngle_deg = …
terrainHeight_ft = …
vehicleSpeed_mps = …

I love this – great post!

What is your thought on using try/catch – and where would you caution people against using it?

I have my own thoughts – but I would like yours :)

Richard, Joseph, and Sarah,

1) Thanks Richard. Indeed I was focusing primarily on actual coding and not the rest of the development process. That is, of course, a very important topic and your book addresses it well.

2) Joseph- I agree about having good naming conventions. Exactly how to agree on conventions can be difficult. I prefer MixedCase or camelCase vs. using an extra character with _ generally, for example. Others don’t share my aversion to _!

3) Sarah-
I like and think try/catch should be used in general. It didn’t make my top list because… not sure… maybe because I am not sure most people are writing code that needs to be robust to the extent of supporting a large group of users. Also, it may be richer than they often need. Sometimes simply issuing an error is enough. Only if you have to do something special after the error is try/catch *required*. If used, I believe it’s best used with the MException syntax. What do you think?

–Loren

Great post, Loren!

@Joseph, I was reading your list, and I noticed that I have the exact same convention as you have.

I agree with many of these points. The one that resonated with me was about error checking. Aside from demos, I tend to create utility functions, so I always make sure that I have solid error checking, using functions like “assert”, “inputParser”, “validateattributes”, and “validatestring”. Writing extremely detailed help is another thing I do. Especially if I’m creating a class, I make sure I format it appropriately so that the HELP/DOC commands will render it correctly.

For #7, what do you think about the following form of load which specifies what variables are appearing in the workspace?
load(‘my_file_name.mat’, ‘myVariable’); % No poof!
Great blog topic. Would love to see a future one on best practices for managing a code project in Matlab, such as many linked functions to do a complicated analysis task.

11. Organize functions into packages or classes when a work directory gets too large, or lots of “helper” functions start appearing.

For other languages, that probably wouldn’t need menition. But I see some very ugly MATLAB directories, and frequntly run into namespace collisions when using code from others.

KE-

You are still poofing the variable. You never “see” it in the file until it is used on the right hand side as a variable. So I don’t care for that usage.

–Loren

Chad-

True, but not in my top group as in my experience, most users are not making large applications.

–Loren

Excellent practices and information from everyone so far. One thing I have done in the past that I try to avoid (mainly for my sanity):

o Do not use nested functions; use a driver function and subfunctions (and please close all of the subfunctions with “end”).

This is mainly to avoid accidental workspace collisions/overwrites from parent functions. And not closing all subfunctions with “end” is a just a huge pet peeve (thanks to the indoctrination of F90).

Troy-

I don’t happen to agree with you about never using nested functions. The shared workspace, when used correctly, can massively reduce memory needs for one. Also, the nested functions can have much simpler and more intuitive apis.

My $0.02,
Loren

Hi and many thanks for this post.
Could you please explain why one should avoid eval (#7)

Best,
Eleftheria

Loren:

Hm, I never considered that, but it makes sense. I guess I’ve become spoiled with 8GB of memory at work.

And I guess the last time I’ve used nested function was for one of the largest projects I’ve ever done (an incompressible, 2D CFD simulation with a 200×200 grid). I’ll consider this in the future.

- Troy Haskin

With regards post http://blogs.mathworks.com/loren/2012/01/13/best-practices-for-programming-matlab/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+mathworks%2Floren+%28Loren+on+the+Art+of+MATLAB%29&utm_content=Google+International#comment-32892

Loren, what you ideally want is a plugin architecture like Visual Studio whereby someone can write a ReSharper addin. Possibly one of the single most productivity and code-clarity beneficial addins I have ever used. Although the “beast of Redmond” is much derided I would urge any language developer to look at the functionality and usability of their IDE.

Hi Loren,
I have 2 questions related to your ‘best practises’

N°1: why do you recommend to avoid the use of Global variables, sometimes it is very convenient?

N°2 Remark:
I have the impression that we must pre-allocate the arrays at the appropriate sizes; I have seen in some functions things like the following example where the size of the array changes at each step of the loop

array0=[0 0 1 1];
For k=1:16
array1 =[array0 array0];
end

Even if it is convenient in some processing, from a point of view of clarity and efficiency I think it is better to make a pre-allocation before the processing

array=zeros(1000,1) for instance

What is your feeling?

I loved the tip about bsxfun; I had seen it once before and forgotten the name. Thank you! Now I’ve recorded it in my own tips and tricks.
Suggestion: we need nsxfun (“n-argument singlet expansion”) as well (or extend bsxfun to more than two args). Example of desired operation:

function rslt = prod3(a,b,c);rslt=a.*b.*c;end % in editor
nsxfun(@prod3,[1 2 3],[4;5],[6;7])
% should return the same thing as
prod3(repmat([1 2 3],2,1), repmat([4;5],1,3), repmat([6;7],1,3))

(I mention a separate function because bsxfun is probably heavily optimized and already published and thus not to be redefined, although when I’m coding and add a new capability to a function, as long as it’s backward compatible I don’t define a new function)

Reply to Chaowei Chen

for k=N:-1:1, array(k)=k;end,

on my computer, the run time is 1/40 of the normal for k=1:N method, thank you for this very good code practice example.

Gaston-

I find Globals make programs very hard to debug, they do not generally change the memory characteristics of a program, the program has only one “state” so you can’t make it re-entrant. Generally using a nested function to contain such variables works better as it limits the exposure to who can tamper with the variables. Another great option, if you write your own classes, is to derive one, possible from handle, depending on what you are doing.

Preallocation is a great idea in MATLAB. MATLAB can be smart in certain ways and detect sizes, but otherwise the growth of an area can be both expensive in time, and wasteful of memory. So I agree about that. For me, preallocation is so obvious to do that I wanted to put things on the list the I may not remember to do.

–Loren

Irl-

Please contact technical support and make an enhancement suggestion. It will be much more potent coming from you than me!

–Loren

A very nice article, and very good to illustrate the difference between coding standard and best practice.

Here are a few of my examples

* For non native English speakers: Name your variables in English

* In general: Name your variables so that you recognize instantly what they mean after you have not seen the code for a whole year.

* comment is divine

* do not put different variables into one vector/matrix, whatever. It will become one big messy soup until you choke in a bite and you can start over from scratch.

* Do no use try and catch constructions. If you think they code might fail, you should change the code until you are sure it will always works. Only exception is file handling (pun not intended)

* There is no need to be careful for every single byte these days, but be conscious of memory usage.

In response to post 12. point 8. on acceptible uses of find for creating a list of indices. I find it much faster to create logical indexing and then use find on the logical index array to get the list.

%logical indices (very fast)
idxLow = X > minRange;
idxHigh = X < maxRange;
idx = and(idxLow, idxHigh);

%list of indices (very fast on logicals)
idx = find(idx);

In response to post 36 in reference to a fancy way of preallocating arrays in this manner

for k=N:-1:1, array(k)=k;end

This is cute and works because matlab must first create an array with N elements in it proceed with the rest of the loop. It would be much clearer to preallocate with acceptible preallocation functions like:

array = zeros(1,N); %Same speed as above
for k=1:N
array(k)=k;
end

array = linspace(1,N,N); %3.5 times faster

So, Loren I would add to your list a specific point opposite to vectorization; avoid using for and while loops where possible as in the example above. Do not use a For loop to create a range, use linspace instead.

Loren, a great post as always!

The tip I’d add to this list is make sure your code is formatted nicely with breaks, tabs, and clear variable names. I frequently help to resolve issues that arise because people don’t bother with formatting and the order of desired operations in complex functions gets accidentally mangled.

I typically use “if/else & error” instead of “try/catch” because I write code used by a small core of people, and if it doesn’t break entirely, I won’t hear about edge cases that are malfunctioning. When edge cases arise that I anticipate but don’t have test data to implement with, then I can solve the issue efficiently by adding the required functionality on the spot. I also try to make code noisy when it breaks.

I follow the “Rule of Repair”: When you must fail, fail noisily and as soon as possible. (http://www.faqs.org/docs/artu/ch01s06.html) I think that most people should read “the art of unix programming” when learning to program. It’s free, tremendously insightful, and fun to read.

Hans:
There are several reasons to use functions instead of scripts. First, they don’t have unintended side affects (when combining scripts, variable names can collide). Second, data and flags are explicitly passed back and forth, with temporary variables getting cleared out of memory automatically. Third, the code can be compiled more efficiently because of the variable name issue (it knows where data is coming from, rather than having to check if a variable exists already and what the type is).

Since functions define the inputs and outputs, it also easier to reuse the code, since you know where things are coming from and going to. Likewise, if you start to document things with comments, the code will have it’s own documentation. You can also encapsulate required sub-functions so that the code is easily portable across systems.

Loren,
Sometimes its diffucult to avoid globals but I understand the need to avoid them.

“Poofing” has certainly caused me problems in the past. I appreciate you listing this one. Poofing also makes it difficult for others to follow the original author’s code.

I love the Profiler but sometimes the code is so fast that profiling is unnecessary.

I must admit that my biggest surprise came from the comments.

There seems to be quite a bit of concern with regards to programming / development time. One of the main reasons to purchase MATLAB/Simulink is that programming / development time is so much less than that of other languages especially when graphics are concerned. There is really no other SW product on Earth that can do so much so easily. If there was, the MW would not have been as successful as it has been for almost 30 years.

I have developed MATLAB applications and Simulink models professionally for 16 years and it has been my experience that the actual development time is barely significant when compared to the amount of time spent on the design of the SW (what shall the SW do), drafting the SW requirements and the inevitable changes to the requirements that come during code development.

Legibility and clarity come from the author’s comments as well as from his/her code but copious comments ought not affect development time that much.

Eddie

I started writing source code in about 1972 and I have written in FORTRAN, Pascal, Basic, C, C+, and others. First, I would like to say that Matlab is the best of the high order languages that I have used. I have also written coding standards for the Air Force for FORTRAN and for Matlab in the current company where I work. What I notice mostly about the best practices listed here is that there is a lot missing. I am not going to try to list all of the standards that I follow, but a few of them might be of interest.
Naming conventions: 1) all functions begin with a capital letter; 2) all parameters and variables begin with a small letter; 3) I prefer a capital letter to separate parts of the name, the underscore just adds unneeded length; 4) select a set of standard units that are to be used throughout the code and change the input units to the standard units at the input function(s) and change the standard program units to the desired units at the output function(s). Do not change units within the program; 5) global should only contain constant values. The global values are the parameters for the model and should be set in a function that defines the meaning of the values as well as setting the value; 6) Along with the use of parameters, never use a real number inline in the code, these are referred to as magic numbers and often difficult to locate and update when changes are needed; 7) Every function should (read must) contain a header consisting of the following information: the purpose of the function, complete description of all input arguments (including units), complete description of all output arguments, the function author, and the version number and date. If the function is complex, then a reference describing the algorithm is preferred.
These are just a small part of the standards that I enforced on my programmers both here and Los Alamos National Labs regardless of the programming languages that were used at the time. There is much more, but I am not going to try to put all of this in the comment. I hope this is interesting to some one.

I find that using globals when I optimising a simulink block parameter in a function is faster though dirty. This is partly due to legacy when I was using the fmins program. I think the ideal solution today is to map the workspace. Are there any easy methods?

One more addition that came to mind this morning.

There is a often a balance between performance and memory usage, facing programmers. I have bought 24 GB of memory for an equivalent of less than a week’s rent of my apartment. The processor I have bought 3 years ago still costs more today.

If you can improve performance by using more memory… do so.

(a) Distinguish carefully — in your mind, and then in the typography — between entities that are allowed to change (dynamic objects with handles) and those that aren’t (“constants”). I generally use ALLCAPS for the constants. If you’re writing a library function for lots of other people to use, you had better not change their objects without warning them!

Lesson: All input arguments should be assumed to be constants until proven otherwise, or unless documented otherwise. For general-use functions, the fact that you don’t think of an array, a string, or a file as a constant is none of your business — it belongs to the user/caller, not to your function, unless you document that it will change. (Yes, I typically write all non-handle input arguments in ALLCAPS, for exactly this reason.)

Refinement: MATLAB will help to manage this when changing arguments that have built-in non-handle types, such as numerical arrays. But it will do so by copying the entire object, possibly exhausting memory. If you rely on this behavior (the nice semantics of MATLAB), you should probably make it clear to the person reading your code later: You are creating a copy of the array, with some different values. That will take time and use memory, and the original values of that array will no longer be available in the code, even if the code-maintainer later decides that they are needed. (Best practice: Never change the value of an input argument. Just use a local variable for the changed version of the argument.)

(b) Be careful about capitalization: Unlike MATLAB, people are NOT case-sensitive — or rather, we use it for much more sophisticated things than simply distinguishing between distinct entities.[*]

So someone trying to understand your code in 6 months may notice the difference between “a” and “A”, which have very different shapes. They may not notice the difference between “s” and “S”, nor between “YourCasedVariableName” and “YourCasedVariablename”. (BTW, in my experience, they will notice underscores.)

Lessons: Use the editor display/MLINT to flag variables that aren’t used. (Maybe you mis-capitalized something?) And don’t depend too much on subtleties like capitalization to keep things straight in the minds of people reading your code later!

[*] Notice that my surname has a capital letter in the middle of it. It does not distinguish me — legally, or any other way — from anyone who uses different capitalization. Rather, it conveys information about my heritage.

What best practices do people have about using structures?

I am reading people’s code where they set a field of a structure in one place, and then set another field of the same structure somewhere else, and then again somewhere else, and by the end of the program I have little idea which fields the structure has ended up with. So I try to pre-initialize structures that I will be building up by doing

s = struct(‘field1′,[],…
‘field2′,[],…

);

In general, I like the struct statement better than

s.field1 = [];
s.field2 = [];

s.fieldn = [];

Loren can you explain why we can’t put a function in a script? I find it convenient for initial development to have your top level main be a script but then I often want to have a function in it and am forced to make the annoying choice of functionalizing the main or putting the function in a separate file.

Jeff-

It’s simply not currently part of the MATLAB language. It’s been requested before and we understand why. It’s something we continue to consider.

The other thing you could do is put your script into a function that doesn’t require any inputs, and have the associated function be a subfunction for the same file.

–Loren

I echo Tom Pressburger’s point — about both structures and arrays (cell or otherwise). Augmenting a structure with new fields, or an array with new lengths (along one or more dimensions), multiple times scattered throughout a function is a recipe for code that is difficult to understand and difficult to maintain. If you can, define those fields or lengths at the beginning.

I am learning Simulink and it appears to violate many of these recommendations. For example, the default is to fill your workspace with every variable the model will use (this could be hundreds, with no way of tracking them). It is hard to execute a Simulink model from within a function rather than from within a script. It seems like you end up using evalin a lot when scripting. Do more experienced Simulink users find this to be the case?

@KE – Many years ago, Simulink was limited to storing data only in the base workspace. Recent releases of Simulink have addressed these issues by creating model workspaces and enabling management of all data through the Model Explorer. Executing a Simulink model from within a function can still be a little awkward, but it is possible to specify the source workspace as the ‘current’ to access variables within the function. I think these capabilities greatly improve the ability to manage data within Simulink. Most experienced Simulink users have an overall strategy for data management, and for data shared across model references, such as bus objects or global data objects, the base workspace is used.

These postings are the author's and don't necessarily represent the opinions of MathWorks.