How to randomly generating a function with math operators and operands

Hi, I am new in matlab. Currently, I am trying to generate random functions with math operators like {+,-,*,/} and operands like {1,2,3,4}. Now I have a cell containing the operators I need. First of all, as the operators are in a cell, how can I use them to generate functions? Also, How can I randomly combine the operators and operands to generate functions? I would appreciate it a lot if someone could help me. Thanks Julie

1 Comment

By "functions", do you mean you want to randomly generate simple expressions with binary operators? E.g., generate expressions like 2*3 or 4/2 randomly? And do you want the result to be a string?

Sign in to comment.

 Accepted Answer

Hi Julie
the answer to your question has 2 parts, 1st the random generation of operands operators, and the 2nd part the function engine that solves the random chains and supplies the results.
Part I
random generation of operands operators
clear all;clc;close all
format long;format compact
ops={'+' '-' '/' '*'} % operators
data=[1:1:9]
amount_ops=6
reps=10 % repetitions
ops_a_do=ops([randi([1 numel(ops)],reps,amount_ops)])
operands=data(randi([1 numel(data)],reps,amount_ops+1))
R=cell(reps,2*amount_ops+1)
for k=1:1:amount_ops+1
for s=1:1:reps
R{s,2*k-1}=operands(s,k)
end
end
for k=1:1:amount_ops
for s=1:1:reps
R{s,2*k}=ops_a_do{s,k}
end
end
R =
10×13 cell array
[3] '/' [2] '*' [9] '+' [3] '+' [1] '-' [3] '-' [4]
[2] '*' [6] '+' [8] '/' [3] '+' [2] '+' [4] '/' [2]
[6] '*' [6] '-' [8] '/' [5] '*' [6] '-' [5] '/' [2]
[6] '*' [1] '*' [5] '/' [6] '-' [3] '+' [7] '-' [9]
[4] '+' [9] '/' [2] '*' [1] '*' [9] '+' [8] '/' [7]
[2] '*' [7] '*' [4] '*' [8] '+' [2] '+' [1] '-' [5]
[9] '/' [7] '/' [2] '*' [6] '/' [9] '+' [2] '+' [9]
[1] '*' [1] '/' [1] '/' [8] '/' [5] '+' [4] '-' [1]
[1] '/' [8] '+' [9] '*' [4] '+' [7] '+' [1] '*' [7]
[2] '-' [9] '/' [3] '/' [5] '/' [9] '/' [5] '*' [7]
Part II
Calculation of results, the engine of the function
R2=NaN([reps 1],'double')
for s=1:1:reps
L=R(s,:)
r0=L{1}
for k=1:1:(length(L)-1)/2
L1=L([2*k-1:1:2*k+1])
op_=L1{2}
L1{1}=r0
switch op_
case ops{1} % +
r0=r0+L1{3}
case ops{2} % -
r0=r0-L1{3}
case ops{3} % /
r0=r0/L1{3}
case ops{4} % *
r0=r0*L1{3}
otherwise
disp('op error');
end
end
R2(s)=r0
end
R2 =
10.5000
6.3333
14.3000
0
9.5000
446.0000
11.4286
3.0250
311.5000
-0.0726
the presentation may be required in rational format
rat(R2)
=
10×20 char array
'11 + 1/(-2) '
'6 + 1/(3) '
'14 + 1/(3 + 1/(3)) '
'0 '
'10 + 1/(-2) '
'446 '
'11 + 1/(2 + 1/(3)) '
'3 + 1/(40) '
'312 + 1/(-2) '
'-0 + 1/(-14 + 1/(4))'
the function itself
  • requires safe checks of the inputs,
  • ranges instead of a cell may be preferred for the input of the operands,
  • and both R, the matrix containing operators and data, as well as the data may be required to be stored in separate files, so you can distribute the R without revealing R2.
You may want the function to return error codes, include time stamps and for instance generate a hash code combining different factors to verify authenticity. Fields for date, author, learning centre, class and distribution list may be also be desired.
It may be also desired to encrypt generated the operators operands matrix as well as the results, and do not disclose until just before exam start time.
At this point the question is solved, leaving the 'chassis' of the function at your discretion.
if you find this answer useful would you please be so kind to consider marking my answer as Accepted Answer?
To any other reader, if you find this answer useful please consider clicking on the thumbs-up vote link
thanks in advance
John BG

8 Comments

Julie
Stephen Cobeldick has posted code with anonymous functions. Would you please confirm that his example
1-2*3-4
means
(((1-2)*3)-4)
that in turn means his example
>> out{1}(1,2,3,4) % the first function
ans =
-9
>> 1-2*3-4 % the first expression
ans =
-9
should be
out{1}(1,2,3,4)
=
-7
John BG
Comment about 'vectorising'
Spending programming time avoiding for while et al loops to perform matrix operations may be preferred by some programmers,
yet sometimes it has some limitations, if not implement correctly, like the code supplied by Stephen Cobeldick
%%QUOTING S Cobeldick code posted at @08:00 am July 30th 2017
opr = '+-*/';
trm = 3; % number of operands
xpr = 4; % number of expressions;
% pick operators:
ido = randi(numel(opr),xpr,trm); % pick random operators
vec = 'a'+(0:trm);
% create expressions:
tmp = repmat('X',xpr,trm*2+1);
tmp(:,2:2:end) = opr(ido);
tmp(:,1:2:end) = ones(xpr,1)*vec;
tmp = num2cell(tmp,2);
% generate functions:
pfx = sprintf(',%c',vec);
pfx = sprintf('@(%s)',pfx(2:end));
out = strcat(pfx,tmp);
out = cellfun(@str2func,out,'Uni',0);
%%END OF CODE QUOTE
the vector opr is chosen while assigning one and only one character per operation. That is done to avoid using a cell to contain the operators list, for the purpose of precisely keeping as simple as possible the anonymous functions.
However Julie mentions in the question that the operators should be in a cell by using the '{' '}'.
If not using a cell to contain the operators list, Mr Colbedick is limiting the operators tagging to single characters per operation.
That in turn means Julie would not be able to name operators with things like
sqr % ()^2
or
sqrt % ()^.5
or
^3
hope it helps
John BG
Stephen I understand what you mean and indeed I completely agree with the operators precedence.
Yet in a context like school competitions, or even a live TV program it's common practice to omit the parentheses, just for the sake of brevity.
In any case it's easy to modify my script to perform the operations in whatever way Julie chooses.
Why don't we just wait for Julie to comment and explain?
John BG
"...it's common practice to omit the parentheses, just for the sake of brevity."
Really? I have never seen this. Can you give a reference or examples of this?
"...in a context like school competitions..."
I was taught BEDMAS at school.
In a test for mental calculation, it happens that the teacher ask step by step for an operation and an operand: "Start with 2", "time 3", "minus 14", "divided by -3" and so on. Then the precedence is ignored. The OP Julie G did not specify clearly, what she wants to achieve. I do not see a reason to assume, that the problem concerns "sqrt()" or the unusual rules of mental calculation contests, or that hash codes, authentication, or encryption is required here.
"{+,-,*,/}" is no valid Matlab code, therefore I cannot predict, if the curly braces mean a cell array and I do not think, that this detail is important.
Danke schön Jan for pointing out there's room for doubt.
In any case, let's wait for Julie to decide, either approach can be implemented with Stephen's script, or with my script. Even both ways can be easily implemented allowing the user to decide.
However in my opinion it's important for Stephen to consider Julie's line
'Now I have a cell containing the operators I need'
And Julie also writes '{' '}' to list the operators so far considered.
So Stephen should use a cell, not a string, for the operators.
Regards
John BG
following, answer including both modes, speed test, or standard arithmetic.

Sign in to comment.

More Answers (2)

This is MATLAB, so there is no point in writing slow and ugly nested loops and using switch statements when vectorized code and indexing is so much simpler and easier. The initial question does not specify very clearly what the output should be, so I read the title "...generating a function..." literally and return function handles with randomly generated sequences of the operators: {+,-,*,/}. This simple code should get you started: you can easily adapt it to your needs.
opr = '+-*/'; % binary operators
trm = 3; % number of operands
xpr = 4; % number of expressions
% pick random operators:
ido = randi(numel(opr),xpr,trm);
vec = 'a'+(0:trm);
% create expressions:
tmp = repmat('X',xpr,trm*2+1);
tmp(:,2:2:end) = opr(ido);
tmp(:,1:2:end) = ones(xpr,1)*vec;
tmp = num2cell(tmp,2);
% generate functions:
pfx = sprintf(',%c',vec);
pfx = sprintf('@(%s)',pfx(2:end));
out = strcat(pfx,tmp);
out = cellfun(@str2func,out,'Uni',0);
The randomly generated expressions are shown in the variable tmp:
>> tmp
tmp =
'a-b*c-d'
'a/b-c-d'
'a*b/c-d'
'a+b+c/d'
and the corresponding anonymous functions are stored in the cell array out:
>> out
out =
@(a,b,c,d)a-b*c-d
@(a,b,c,d)a/b-c-d
@(a,b,c,d)a*b/c-d
@(a,b,c,d)a+b+c/d
This allows us to easily test the output ourselves:
>> out{1}(1,2,3,4) % the first function
ans =
-9
>> 1-2*3-4 % the first expression
ans =
-9
Edit use this simple version for a cell array of binary operators:
opr = {'+','-','.*','./'}; % binary operators
trm = 3; % number of operands
xpr = 4; % number of expressions
% pick random operators:
ido = randi(numel(opr),xpr,trm);
vec = char('a'+fix(0:0.5:trm));
% create expressions:
tmp = repmat(num2cell(vec),xpr,1);
tmp(:,2:2:end) = opr(ido);
tmp = cellfun(@(c)[c{:}],num2cell(tmp,2),'uni',0);
% generate functions:
pfx = sprintf(',%c',vec(1:2:end));
pfx = sprintf('@(%s)',pfx(2:end));
out = strcat(pfx,tmp);
out = cellfun(@str2func,out,'Uni',0);
It has exactly the same outputs: out is a cell array of functions handles, and tmp shows the randomly constructed expressions.

2 Comments

Stephen
if you don't use a cell to contain the operators list, you limit the operators to single characters, which in turn means that you cannot name operators with thinks like
sqr
or
sqrt
or
^3
John BG
@John BG: yes, I am aware that the code I wrote only works with single character binary operators. It is trivial to alter the code to use a cell array of binary operators, and change the anonymous functions to suit. Given the very vague specifications there is no point in making more code more complex than it needs to be for the given specifications.
"...which in turn means that you cannot name operators with thinks like sqr or sqrt or ^3"
Agreed. That is because I wrote the code to fit the specifications given in the question. Note that your code also cannot handle unary operators, so your list of non-parsed operators equally applies to your answer as well. Writing a parser that can handle unary and binary operators in any sequence is not trivial task.
PS: I could not find the sqr operator in the list of MATLAB functions. Can you please show a reference for it?

Sign in to comment.

Hi Julie
the following script generates an amount of ops_a_do operations using the operands listed in cell ops, repeating reps times.
  • When variable speed_contest=1 the script skips parentheses. For instance 1+2*3 = (((1+2))*3)=9
  • if speed_contest=0, then 1+2*3=7
The inputs
clear all;clc;close all
format long;format compact
ops={'+' '-' '/' '*'} % operators
data=[1:1:9]
amount_ops=6
reps=10 % repetitions
speed_contest=0 % choose, 1: 1+2*3 = (((1+2))*3)=9 2: 1+2*3=7
the basic function
function [R,R2]=gen_ops(ops,data,amount_ops,reps,speed_contest)
ops_a_do=ops([randi([1 numel(ops)],reps,amount_ops)])
operands=data(randi([1 numel(data)],reps,amount_ops+1))
R=cell(reps,2*amount_ops+1)
for k=1:1:amount_ops+1
for s=1:1:reps
R{s,2*k-1}=operands(s,k)
end
end
for k=1:1:amount_ops
for s=1:1:reps
R{s,2*k}=ops_a_do{s,k}
end
end
R
% Calculation of results
R2=NaN([reps 1],'double')
switch speed_contest
case 1 % speed test on, 1+2*3 = (((1+2))*3)=9
for s=1:1:reps
L=R(s,:)
r0=L{1}
for k=1:1:(length(L)-1)/2
L1=L([2*k-1:1:2*k+1])
op_=L1{2}
L1{1}=r0
switch op_
case ops{1} % +
r0=r0+L1{3}
case ops{2} % -
r0=r0-L1{3}
case ops{3} % /
r0=r0/L1{3}
case ops{4} % *
r0=r0*L1{3}
otherwise
disp('op error');
end
end
R2(s)=r0
end
case 0 % speed test off, 1+2*3=7
for s=1:1:reps
L=R(s,:)
L2=[]
for k=1:1:length(L)
if ~ischar(L{k}) L2=[L2 num2str(L{k})]; end
if ischar(L{k}) L2=[L2 L{k}]; end
end
R2(s)=evalin('base',L2)
end
otherwise
disp('speed_contest var out of range error')
end
R2
end
if you find this answer useful would you please be so kind to consider marking my answer as Accepted Answer?
To any other reader, if you find this answer useful please consider clicking on the thumbs-up vote link
thanks in advance
John BG

2 Comments

Hi John, Thanks a lot for your answer. It helped me a lot. Sorry for replying you so late as I did not work for some days. Actually, I am doing genetic programming with matlab, which I am really not very familiar with. Do you know anything about genetic programming in matlab, especially the toolbox "GP_OLS".
Hi Julie
Thanks for accepting my answer
A.-
I don't have experience with MATLAB applied to genetics, but I am aware that you can use MATLAB to compile data obtained from laboratory measurements, directly from the instruments, and then validate or improve whatever simulation or model you have.
B.-
Please note that some forum contributors had a bit of discussion about whether you wanted conventional arithmetic 1+2*3=7 or you were intending to use parentheses skipping, that is sometimes used in (human) speed competitions, where 1+2*3 really means ((1+2)*3)=9
Julie, for the sole purpose of clarifying this point, would you please be so kind to add a comment on this regard?
C.-
note that today I have added a very basic function that includes both arithmetic, with command evalin, and a simple manual switch with variable speed_contest.
D.-
Literature References that include, or may include related MATLAB code
Found the following links, perhaps you probably already have them all, then for the readers:
1.-
this journal, Genetic programming for the identification of nonlinear input-output models, by Madar, Abonyi, Szeifert
claims to have a freely available implementation in MATLAB that specifically mentions Genetic Programming and OLS estimation tools, follow this link
2.-
the book: Graph Based Clustering and Data Visualisation Algorithms, by Vathy-Fogarassy, Abonyi. Springer
has MATLAB examples are available for download in this page too.
3.-
Same for book: Cluster analysis for data mining and system identification, by Abonyi, Feil, Birkhäuser Verlag, has a Fuzzy Clustering and Data Analysis Toolbox
again MATLAB examples and toolbox detailed examples are freely available.
Regards
John BG

Sign in to comment.

Asked:

on 29 Jul 2017

Edited:

on 23 Aug 2017

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!