20
\$\begingroup\$

MATL is a golfing language created by Luis Mendo. MATL has proven to be highly competitive, often beating submissions in other golfing languages such as Pyth, CJam and Jelly.

What are some useful tips for golfing in MATL? (As always, one tip per answer, please!)

\$\endgroup\$
  • 5
    \$\begingroup\$ It is definitely a great advantage if you know some Matlab/Octave. Some tricks from Tips for golfing in Matlab and Tips for golfing in Octave used in MATL too. \$\endgroup\$ – flawr Apr 22 '16 at 6:34
  • \$\begingroup\$ Suggestion: it looks like accumarray (XQ) can be quite powerful (possibly even more than in MATLAB/Octave since those length function handles have handy numeric codes), but I don't know it well enough to illustrate with good examples. If it actually is useful, could someone create an answer with ideas on how to use it? \$\endgroup\$ – sundar Jul 10 '18 at 14:22

12 Answers 12

7
\$\begingroup\$

Know the predefined literals

Although some of them keep information when copied to the clipboard, they all have a predefined value.

  • F, pushes 0 (actually False)
  • T, pushes 1 (actually True)
  • H, pushes 2 (predefined clipboard value)
  • I, pushes 3 (predefined clipboard value)
  • K, pushes 4 (predefined clipboard value)
  • J, pushes 0 + 1j (predefined clipboard value)

Not sure if I have covered all predefined values though.

\$\endgroup\$
  • \$\begingroup\$ Just for completeness (and in case you want to add to your answer): each level of clipboard L also has a predefined value, but they are intended for special uses (rather than common, general values). For example, 1L gives [1 0] (which is used as index 1:end), 2L gives [0 -1 1] (for 1:-1:end). Also, functions l and O take 0 inputs by default and produce 0 and 1 respectively \$\endgroup\$ – Luis Mendo Apr 21 '16 at 20:41
  • \$\begingroup\$ I don't see how this is useful... Can't I just write 4? \$\endgroup\$ – Cyoce Apr 21 '16 at 21:08
  • \$\begingroup\$ @Cyoce The usefulness is to avoid a space as separator. If you want to push 1, then 4, 14 won't do. You'd need 1 4. Or 1K to save one byte \$\endgroup\$ – Luis Mendo Apr 21 '16 at 21:44
  • \$\begingroup\$ @LuisMendo ah, I see. I guess I assumed it was using the 1-digit number only method (not sure why) \$\endgroup\$ – Cyoce Apr 21 '16 at 21:46
  • 1
    \$\begingroup\$ Another case when K instead of 4 is handy is: 1-4 means: push 1, then push -4; whereas 1-K means: push 1, subtract from whatever is below in the stack, then push 4 \$\endgroup\$ – Luis Mendo Apr 21 '16 at 21:51
5
\$\begingroup\$

The & Meta-Function (Alternative Input / Output Specification)

The traditional way to specify the number of input arguments to pass to a function is to use the $ meta-function

2$:     % Two-input version of :

Similarly, to specify the number of output arguments you can use the # meta-function specifying either the number of output arguments,

2#S     % Two-output version of sort

or if you pass a number that is greater than the number of output arguments defined for a function, only the mod(N, numberOfOutputs) + 1 output is supplied.

4#S     % Get only the second output of sort

You can additionally specify a logical array as the input to # to retrieve only specific output arguments.

TFT#u   % Three output version of unique and discard the second output

All of these input / output specifications are handy but they drive up your byte-count very quickly. To deal with this, MATL introduced the & meta-function in the 17.0.0 release. This & meta-function acts as a shortcut for a particular input or output specification for a function. Let's see what that means.

In our example above, we wanted to use the two-input version of : (creates a vector of equally-spaced values). While the default number of input arguments to : is 1 (creates an array from [1...N]), it is very common that a user would want to specify the start value of the range which requires the second input. So for :, we have defined & to be a shortcut for 2$.

10      % Push 10 to the stack
12      % Push 12 to the stack
2$:     % Create an array: [10, 11, 12] 

Now becomes the following, saving a byte!

10 12 &:

How can we determine what the alternate number of arguments is?

The input / output specification that & translates to is function specific such that we optimize the byte-savings.

The input / output argument section of the help description for each function has been updated to indicate what this alternative number of inputs / outputs is (if any). The possible number of input or output arguments are displayed as a range and the default values for each are shown in parentheses. The input / output spec that can be substituted with & is shown after the / character within the parentheses.

Here is the input / output argument section of the help description for :

 +- Min-Max range of # of inputs
 |        +----- Alt. Default # of inputs
 |        |
 V        V
1--3 (1 / 2); 1 <--- Possible / Default # of outputs
      ^       
      |       
  Default # of inputs

How did you determine what & means for each function?

Very carefully. Using the StackExchange API, we were able to download all MATL answers that have ever been used in a PPCG challenge. By parsing each of the answers, we were then able to determine the frequency with which each input / output spec was used for each function. Using this information we were then able to objectively identify the input / output specification the & meta-function should represent for each function. Sometimes there was no clear winner, so many functions currently don't have & defined.

Here is the script we used (unfortunately it's written in MATLAB and not MATL).

And here is an example of the histogram of $/# usage

\$\endgroup\$
  • 1
    \$\begingroup\$ This feature was suggested by @Suever. Originally & was going to mean "increase number of inputs by 1 with respect to the default". His suggestion turned out to be much more useful \$\endgroup\$ – Luis Mendo Sep 19 '16 at 22:03
5
\$\begingroup\$

Get familiar with MATL's truthy/falsy definitions

While true (T) and false (F) clearly represent truthy and falsy output, respectively, the widely agreed upon definition of truthy/falsy gives us a little bit more flexibility in MATL.

The definition states:

if (x)
    disp("x is truthy");
else
    disp("x is falsy");
end

So we can write a quick MATL truthy/falsy test which will loop through all inputs and display whether they were considered to be truthy or falsy

` ? 'truthy' } 'falsey' ]DT

Here is an online version.

What this means in MATL

What this actually translates to in MATL (and therefore in MATLAB and Octave) is that a condition is considered to be true if if it is non-empty and real components of all its values are non-zero. There are two parts to this that should be emphasized.

  1. Non-zero: This means precisely that, not equal to zero (==). This includes positive numbers, negative numbers, non-null characters, etc. You can easily check by converting a given value to a logical value (g) or you can use ~~

    F           % Falsy
    T           % Truthy
    0           % Falsy
    1           % Truthy
    2           % Truthy
    -1          % Truthy
    'a'         % Truthy
    ' '         % Truthy (ASCII 32)
    char(0)     % Falsy  (ASCII 0)  
    
  2. All values: Typically we think of scalars as being true or false, but in MATL, we can evaluate scalars, row vectors, column vectors, or even multi-dimensional matrices and they are considered to be truthy if and only if every single value is non-zero (as defined above), otherwise they are falsy. Here are a few examples to demonstrate

    [1, 1, 1]           % Truthy
    [1, 0, 0]           % Falsey
    [1, 1, 1; 1, 1, 1]  % Truthy
    [1, 0, 1; 1, 1, 1]  % Falsey
    'Hello World'       % Truthy
    

The one edge case, as mentioned above, is an empty array [], which is always considered to be falsy (example)

How can I use this to golf better?

If the challenge simply mentions that your output should be truthy or falsy, you can likely exploit the definition above to shave a few bytes off of your answer. To save confusion, it is recommended that you include a link to the online truthy/falsy test above in your answer to help explain how MATL truthy/falsy values work.

A couple of specific examples:

  • An answer ending in A. If the challenge requires a truthy or falsy output and you end your answer in all (A) to create a scalar, you can remove this last byte and your answer will remain correct (unless the output is [] since [] is false but []A is true).

  • Ensuring that an array contains only one unique value: Uses &= in place of un1=. If all values in an array are equal, a broadcasted element-wise equality comparison will yield an N x N matrix of all ones. If all values are not equal, this matrix will contain some 0 values and therefore be considered falsy.

\$\endgroup\$
4
\$\begingroup\$

Implicit Input

Most functions accept some number of input. These inputs are taken from the top of the stack. If the top of the stack does not contain enough arguments, it will draw the remaining argument from the input. (See Section 7.3 in the documentation) I'd like to cite the original explanation:

Implicit inputs can be viewed as follows: the stack is indefinitely extended below the bottom, that is, at positions 0, −1, −2, ...with values that are not initially defined, but are resolved on the fly via implicit input. These inputs are asked from the user only when they are needed, in the order in which they are needed. If several inputs are required at the same time they follow the normal stack order, that is, the input that is deepest in the (extended) stack is entered first.

\$\endgroup\$
  • 2
    \$\begingroup\$ Implicit input is a feature that was suggested by @flawr \$\endgroup\$ – Luis Mendo Apr 22 '16 at 8:28
  • 6
    \$\begingroup\$ @flawr must be a really clever guy. :D \$\endgroup\$ – flawr Apr 22 '16 at 8:37
3
\$\begingroup\$

Logical arrays can often be used as numeric arrays

You can often use "TF" notation instead of array literals of zeros and ones. For example, FTF is the same as [0,1,0], only that FTF produces logical values, not double values. This is usually not a problem, as any arithmetical operation will treat logical values as numbers. For example, FTFQ gives [1,2,1] (Q is "increase by 1").

In some cases, conversion of a number to binary may be shorter. For example, [1,0,1], TFT and 5B are the same; again with the caution that the latter two are logical values.


A case where the difference between TF (logical) and [1 0] (numeric) matters is when used as indices. An array of type logical used as an index means: pick elements corresponding to T, discard those corresponding to F. So [10 20]TF) produces 10 (select the first element), whereas [10 20][1 0]) produces [10 20] (the index [1 0] has the interpretation of 1:end, that is, pick all elements of the array).

\$\endgroup\$
3
\$\begingroup\$

For loop of size n-1

Consider replacing

tnq:"...

with

td"...

to save up to an entire byte or more.

\$\endgroup\$
  • \$\begingroup\$ @Luis true! I thought that one might need the original vector that is being looped, but that's not possible in the first approach either. Will remove that remark. \$\endgroup\$ – Sanchises Sep 19 '16 at 15:14
  • \$\begingroup\$ But you don't necessarily save 1 byte; you save 1 or 2 depending on whether you need @ / X@ within the loop or not. Maybe you can just say "to save bytes" \$\endgroup\$ – Luis Mendo Sep 19 '16 at 15:30
3
\$\begingroup\$

Move things from after the loop to within the loop, to exploit implicit end

Loop end statements, ], can be left out if there is no code after them. They are filled by the MATL parser implicitly.

So if you can move things from after the loop to within the loop you can to save the final ].

As a specific example, the following code finds how many trailing zeros there are in the factorial of a number N (see it here):

  • The code loops from 1 to N.
  • For each of those numbers it computes its prime factors, and determines how many times 5 is present.
  • The answer is the accumulated number of times 5 appears (this works because for each 5 there is at least one 2).

The first idea was :"@Yf5=]vs (note that there are statements after the loop):

:      % Range from 1 to implicit input
"      % For each number in that vector
  @    %   Push that number
  Yf   %   Vector of prime factors (with repetitions)
  5=   %   True for entries that equal `5`, and `false` for the rest
]      % End for
v      % Concatenate all vectors as a column vector
s      % Sum. Implicitly display

Since v by default concatenates all stack contents, it can be moved into the loop. And since addition is associative, s can be moved too. That leaves ] at the end of the code, and thus it can be omitted: :"@Yf5=vs:

:      % Range from 1 to implicit input
"      % For each number in that vector
  @    %   Push that number
  Yf   %   Vector of prime factors (with repetitions)
  5=   %   True for entries that equal `5`, and `false` for the rest
  v    % Concatenate all vectors so far as a column vector
  s    % Sum. Inplicitly end loop and display
\$\endgroup\$
  • \$\begingroup\$ i dont know a dime of this hieroglyphic-alike written language but i ll reserve a great part of my time studying it next three months maybe. \$\endgroup\$ – Abr001am May 13 '16 at 16:36
  • \$\begingroup\$ @Agawa001 :-) You'll find it's quite similar to Matlab. You can also ask or comment here \$\endgroup\$ – Luis Mendo May 13 '16 at 17:00
3
\$\begingroup\$

Shorter way to define an empty numeric array, if the stack is empty

To push an empty numeric array you normally use []. However, if the stack is empty you can save a byte using v. This function by default concatenates all stack contents vertically, so if the stack is empty it produces the empty array.

You can see it in action for example here.

\$\endgroup\$
2
\$\begingroup\$

Some functions are extended compared with MATLAB or Octave

If you come from MATLAB or Octave, you'll find many MATL functions are similar to functions in those languages. But in quite a few of them functionality has been extended.

As an example, consider MATLAB's reshape function, which in MATL corresponds to e. The code snippets reshape([10 20 30 40 50 60], 2, 3) and reshape([10 20 30 40 50 60], 2, []) respectively mean "reshape the row vector [10 20 30 40 50 60 into a 2×3 matrix", or "into a 2-row matrix with as many columns as needed". So the result, in both cases, is the 2D array

10    30    50
20    40    60

Something like reshape([10 20 30 40 50 60], 2, 2) or reshape([10 20 30 40 50 60], 5, []) would give an error because of incompatible sizes. However, MATL will remove elements in the first case (try it online!) or fill with zeros in the second (try it online!) to produce, respectively,

10 30
20 40 

and

10 60
20  0
30  0
40  0
50  0

Other functions that have extended functionality in comparison with their MATLAB counterparts are (non-exhaustive list) S (sort), Yb (strsplit), m (ismember), h (horzcat), v (vertcat), Zd (gcd), Zm (lcm), YS (circshift), YA (dec2base), ZA (base2dec), Z" (blanks).

\$\endgroup\$
1
\$\begingroup\$

Get the index of the first non-zero element, if any

The f function gives the indices of all non-zero elements of an array. Often you want the index of the first nonzero element. That would be f1): apply f and pick its first element. But if the original array doesn't contain any non-zero value f will output an empty array ([]), and trying to pick its first element will give an error.

A common, more robust requirement is to obtain the index of the first element if there is at least one, and [] otherwise. This could be done with an if branch after f, but that's byte-expensive. A better way is fX<, that is, apply the minimum function X< to the output of f. X< returns an empty array when its input is an empty array.

Try it online! (Note that an empty array is not displayed at all). Or see an example of this at work here.

\$\endgroup\$
1
\$\begingroup\$

Generate a range as long as a given array

TL;WR: use f instead of n: if the array only has nonzero elements.


It is often the case that one needs to generate an array [1 2 ... L] where L is the number of elements of a given array. The standard way to do that is n:. For example, the code tn:* takes a numeric vector as input and computes each entry multiplied by its index.

If the given array is guaranteed to only contain nonzero entries (for example, it is formed by positive integers, or is a string with printable characters), n: can be replaced by f, which produces an array with the indices of nonzero entries. So the above code becomes tf*, which saves 1 byte.

Some more elaborate examples: 1, 2, 3.

\$\endgroup\$
1
\$\begingroup\$

Efficiently defining numeric array literals

Here are a few ways that can be used to save bytes when defining numeric array literals. Links are given to example answers that use them. These have been obtained using the analytics script created by @Suever.

Concatenation and predefined literals

For arrays with small numbers you can sometimes use concatenation (functions h and v), as well as predefined literals to avoid using spaces as separators: compare [2 4], 2 4h and 2Kh, all of which define the array [2 4]. Similarly, 2K1v with an empty stack defines [2; 4; 1]. Example.

Letters within numeric array literals

For slightly larger numbers you can save spaces exploiting the fact that some letters have numeric meanings within array literals. So instead of [3 5 2 7;-4 10 12 5] you can use [IAHC;dX12A]. Example.

Specifically, within array literals,

  • O, l, H I K have their usual meanings 0, ..., 4
  • A, ..., E mean 5, ..., 9
  • X means 10
  • a, ... d mean -1, ..., -4
  • J and G mean 1j and -1j
  • P means pi
  • Y means inf
  • N means NaN.

String and consecutive differences

For larger numbers, defining a string and computing its consecutive differences (with d) can help: instead of [20 10 35 -6] you can use '!5?b\'d. This works because d uses the code points of the chars for computing the differences. Example.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.