Tips for golfing in MATLAB

14

6

What general tips do you have for golfing in MATLAB? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to MATLAB (e.g. "remove comments" is not an answer). Please post one tip per answer.

RAM

Posted 2013-10-23T06:47:29.540

Reputation: 797

Memoizing functions in MatLab – mbomb007 – 2016-10-26T15:15:48.440

3

Related, but not a duplicate: Tips for golfing in Octave

– Dennis Jaheruddin – 2014-01-29T10:15:46.577

Answers

10

Something that one must know before starting to golf:

In MATLAB calculations a character behaves the same as its ascii code.

'abc' - 'a'  % Returns: [0 1 2]
'123' - '0'  % Returns: [1 2 3]
'“' == 8220  % Returns: 1 (logical)
'a':'e'==100 % Returns: [0 0 0 1 0] (logical)

Dennis Jaheruddin

Posted 2013-10-23T06:47:29.540

Reputation: 1 848

9

Shortening property names

In MATLAB, strings identifying properties can be shortened as long as it does not result in ambiguity.

plot(X,'C','k') % Ambiguous property found.
plot(X,'Co','k') % Expands to Color  (black)

This actually won me a challenge :)

Sanchises

Posted 2013-10-23T06:47:29.540

Reputation: 8 530

2Very nice, though the answer is correct I want to emphasize that this applies to the name of name, value pairs as shown above. (So not to things like sort(rand(4,1),'descend')) – Dennis Jaheruddin – 2015-07-30T09:53:53.227

1It does apply to some of those things too, like conv(1:5,[1 1],'s') instead of conv(1:5,[1 1],'same') – Luis Mendo – 2016-12-27T02:03:50.677

6

Casting as char can be done by concatenation with a char:

x='a'+magic(5) % Array with character codes of several letters

char(x) % The standard way
['' x] % The compact way

Though it only saves one char, this can be used quite frequently.

Dennis Jaheruddin

Posted 2013-10-23T06:47:29.540

Reputation: 1 848

5

Strings are just character row vectors. This means that instead of

for i=numel(str)
    a=str(i)
    ...
end

you can simply write

for(a=str)
    ...
end

First time I used this: https://codegolf.stackexchange.com/a/58387/32352

Sanchises

Posted 2013-10-23T06:47:29.540

Reputation: 8 530

4

Roots of unity via discrete Fourier transform

Given a positive integer n, the standard way to generate the n-th roots of unity is

exp(2j*pi*(0:n-1)/n)

This gives the roots starting at 1 and moving in the positive angular direction. If order doesn't matter, this can be shortened to

exp(2j*pi*(1:n)/n)

Since exp(2j*pi/4) equals the imaginary unit (j), this can be written more compactly as follows (trick due to @flawr):

j.^(4*(0:n-1)/n)

or

j.^(4*(1:n)/n)

But the discrete Fourier transform provides an even shorter way (thanks to @flawr for removing two unnecessary parentheses):

fft(1:n==n)

which gives the roots starting at 1 and moving in the positive angular direction; or

fft(1:n==2)

which starts at 1 and moves in the negative angular direction.


Try all of the above here.

Luis Mendo

Posted 2013-10-23T06:47:29.540

Reputation: 87 464

Great trick! You can even golf it down to fft(1:n==2) – flawr – 2017-10-16T15:13:44.367

@flawr I never know the precedence rules... Thanks! – Luis Mendo – 2017-10-16T15:19:07.157

3

Related, but not identical tips for Octave.

A little known and little used feature of both MATLAB and Octave is that most builtin functions can be called without parentheses, in which case they will treat whatever follows it as a string (as long as it doesn't contain spaces). If it contains spaces you need quotation marks. This can frequently be used to save a byte when using disp:

disp('Hello, World!')
disp 'Hello, World!'

Other, less useful examples include:

nnz PPCG
ans = 4

size PPCG
ans = 1  4

str2num 12
ans = 12

I've actually used this twice in the "How high can you count?"-challenge:

strchr sssssssssssssst t

is equivalent to strchr('sssssssssssssst','t') and returns 15.

nnz nnnnnnnnnnnnnn

is equivalent to nnz('nnnnnnnnnnnnnn') and returns 14.

Stuff like gt r s works too (equivalent to 'r'>'s' or gt('r','s').

Stewie Griffin

Posted 2013-10-23T06:47:29.540

Reputation: 43 471

3

nnz can sometimes save you a few bytes:

  • Imagine you want the sum of a logical matrix A. Instead of sum(sum(A)) or sum(A(:)), you can use nnz(a) (nnz implitictly applies (:)).
  • If you want to know the number of elements of an array, and you can be sure there are no zeros, instead of numel(x) you can use nnz(x). This is applicable for instance if x is a string.

Luis Mendo

Posted 2013-10-23T06:47:29.540

Reputation: 87 464

3

Iteration over vectors in matrices.

Given a set of vector as matrix, you can actually iterate over them via a single for loop like

for v=M
    disp(v);
end

while "traditionally" you probably would have done it like

for k=1:n
    disp(M(:,k));
end

I've only learned about this trick just now from @Suever in this challenge.

flawr

Posted 2013-10-23T06:47:29.540

Reputation: 40 560

2

2D Convolution Kernels

This is maybe a niche topic, but apparently some people like to use convolution for various things here. [citation needed]

In 2D following kernels are often needed:

0 1 0
1 1 1
0 1 0

This can be achieved using

v=[1,2,1];v'*v>1 %logical
v=[1,0,1];1-v'*v  %as numbers

which is shorter than

[0,1,0;1,1,1;0,1,0]

Another kernel often used is

0 1 0
1 0 1
0 1 0

which can be shortened using

v=[1,-1,1];v'*v<0   % logical
[0,1,0;1,0,1;0,1,0] % naive verison

flawr

Posted 2013-10-23T06:47:29.540

Reputation: 40 560

Second kernel as numbers, same byte count: toeplitz([0 1 0]) – Luis Mendo – 2019-03-27T09:55:23.783

2

I quite often find myself using meshgrid or ndgrid, let's say we want to compute a mandelbrot image, then we initialize e.g.

[x,y]=meshgrid(-2:1e-2:1,-1:1e-2,1)

Now for the mandelbrot set we need another matrix c of the size of x and y but initialized with zeros. This can easily be done by writing:

c=x*0;

You can also initialize it to another value:

c=x*0+3;

But you can actually save some bytes by just adding another dimension in meshgrid/ndgrid:

[x,y,c]=meshgrid(-2:1e-2:1,-1:1e_2,1, 0); %or for the value 3
[x,y,c]=meshgrid(-2:1e-2:1,-1:1e_2,1, 3);

And you can do this as often as you want:

[x,y,c1,c2,c3,c4,c5]=meshgrid(-2:1e-2:1,-1:1e_2,1, 1,pi,exp(3),1e5,-3i)

flawr

Posted 2013-10-23T06:47:29.540

Reputation: 40 560

Note that in the meantime there is automatic broadcasting: In many cases the first example could be replaced by x=-2:1d-2:1;y=x'. – flawr – 2020-02-04T08:34:36.267

2

The built-in ones and zeros are a typically a waste of space. You can achieve the same result by simply multiplying an array/matrix (of the desired size) by 0 (to get the output of zeros) and add 1 if you want the output of ones.

d = rand(5,2);

%// Using zeros
z = zeros(size(d));

%// Not using zeros
z = d*0;

%// Using ones
o = ones(size(d));

%// Not using ones
o = 1+d*0

This also works if you want to create a column or row vector of zeros or ones the size of one dimension of a matrix.

p = rand(5,2);

z = zeros(size(p,1), 1);
z = 0*p(:,1);

o = ones(size(p, 1), 1);
o = 1+0*p(:,1);

If you want to create a matrix of a specific size you could use zeros but you could also just assign the last element to 0 and have MATLAB fill in the rest.

%// This
z = zeros(2,3);

%// vs. This
z(2,3) = 0;

Suever

Posted 2013-10-23T06:47:29.540

Reputation: 10 257

2I like to use ~(1:n) for 1-d zero vectors. – sintax – 2016-06-20T19:51:55.653

0

Summation of a sequence of functions

  • For summing up functions f(x_n) where n is a vector of consecutive integers, feval is adviced rather than symsum.

    Syms x;symsum(f(x),x,1,n);
    Sum(feval(@(x)f(x),1:n));
    

    Notice that an elementary operation .* and ./ is necessary instead of pairwise binary operations * and /

  • If the function can be naively written no one from either last ways is suitable.

    for example if the function is log you can simply do: sum(log(1:n)) , which represents:

    Sum(f(1:n));
    

    for relatively sophisticated functions as log(n)/x^n you can do:

    Sum(log(1:n)./5.^(1:n))
    

    and even shorter in some cases when a function is longer as f(x)=e^x+sin(x)*log(x)/x....

    Sum(feval(@(y)e.^(y)+sin(y).*log(y)./y,1:n))
    

    that is remarkably shorter than sum(feval(@(y)e.^(1:n)+sin(1:n).*log(1:n)./(1:n),1:n))


Note: This trick can be applied for other inclusive operators as prod or mean


Abr001am

Posted 2013-10-23T06:47:29.540

Reputation: 862