You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How to write one universal function to evaluate many equations?
5 views (last 30 days)
Show older comments
I am working on verifying whether if equations are valid over a large data set. The challenge is that the number of equations to be verified is huge even though they are simple arithmetic equations and identities. In order to avoid writing a different function for each equation, I try to represent an equation as a 'model' and write only one universal function to eval each model. Here is a toy example to explain what I intend to do. My questions are 1.) whether if my approach is generally in right direction 2.) is there any way to avoid eval( ) in function foo( )? Thanks for your insights!
x = 7;
y = 3;
modelA = [x, y; "+", "-"];
foo(modelA)
ans = 4
z = -21;
modelB = [x, y, z; "-", "*", "=="];
foo(modelB)
ans = logical
1
function out = foo(model)
data = string(model(1,:));
operators = model(2,:);
a = strcat(operators, data);
out = eval(strcat(a{:}));
end
15 Comments
Simon
on 2 Jul 2023
Edited: Simon
on 2 Jul 2023
The real problem I work on is checking whether if numbers from many financial statements do satisfy accounting equations. For example, liability + equity == asset (or not). There are maybe over a hundred or more similar identities. And in other cases, I would like to get ratios. I could certainly write function for each accounting equation; as a matter of fact, I have done a couple of that. Then I found this task is too tedious. Othere disadvantages include 1.) function naming and tracking would be out of control and 2.) accounting equations and their purposes are hidden inside functions, which I feel uncomfortable about. Any suggestion?
Stephen23
on 2 Jul 2023
Edited: Stephen23
on 2 Jul 2023
"I could certainly write function for each accounting equation; as a matter of fact, I have done a couple of that. Then I found this task is too tedious."
I don‘t see that it makes any difference: if you can define those string arrays then you can just as easily define some anonymous functions e.g. using STR2FUNC.
"Othere disadvantages include 1.) function naming and tracking would be out of control"
The approach you show in your question also requires lots of individually-named functions. You could easily avoid that with a cell array of anonymous functions or function handles. Or just one function with suitable SWITCH or other logical operations to perform the calculations. Or some suitable nesting of local functions, called based on some logical criteria.
"2.) accounting equations and their purposes are hidden inside functions, which I feel uncomfortable about."
Those are benefits: Mfile functions allow you to neatly and efficiently encapsulate some functionality and provide a documented interface, as well as limitless help, comments, etc. Calling functions is also very efficient. Your string arrays provide none of those benefits.
Simon
on 2 Jul 2023
Edited: Simon
on 2 Jul 2023
@Stephen23 The cell array of anonymous functions seem to be a great idea. I will try it out. Thanks!
A quck array of anonymous function is scribbled. It looks neat and managable.
C = ["@(x, y, z) x-y==z"; "@(x, y) x/y"]
C = 2×1 string array
"@(x, y, z) x-y==z"
"@(x, y) x/y"
foo = str2func(C(1));
foo(3,2,1)
ans = logical
1
goo = str2func(C(2));
goo(4, 5)
ans = 0.8000
John D'Errico
on 2 Jul 2023
Edited: John D'Errico
on 2 Jul 2023
You are going to have many more problems. That is, now you are talking about ratios, but then you are testing for exact equality. That is a bad idea, as you should never tyest for exact equality of floating point numbers. Those tests will unpredictably fail, and then you will be left scratching your head, eventually coming back here to understand the concept I just mentioned. NEVER TEST FOR EXACT EQUALITY BETWEEN FLOATING POINT NUMBERS.
I'd suggest you start rethinking what you need to do, and find a better way than using eval anyway. Eval is slow as hell. It will surely cause you problems down the line too.
For example, you might decide to reduce this to a set of generic expresssions. Now, write one function for each of those generic classes. Pass in your variables, get a result. In the case where a ratio is involved, then you will probably need to apply a tolerance on the result.
Stephen23
on 2 Jul 2023
How many variables do these formulas refer to? If there are many, it might be easier to pass them in a scalar structure and let each function decide for itself which field’s it wants to use.
Simon
on 2 Jul 2023
@Stephen23 'How many variables do these formulas refer to?' It ranges from 3 to 7. In the simplest one, L+E=A, there are three; in more fine-grained equations for sub-factors of, say 'current asset == cash equvalents + notes + inventories + ...' and 'liabilities', there could be more than 5 variables. I couldn't use the number of variables to discern equations.
Because accounting equations have hirachical structure, I hope my codes could adapto that. Like this equation Assets = Capital introduced + (Income – Expenses) – Drawings + Liabilities; or (Income - Expenses) could be replaced by a higher variable. This is one of the reasons I try to find an alternative approach, which would by-pass writing a function for each equation.
Simon
on 2 Jul 2023
Edited: Simon
on 2 Jul 2023
@John D'Errico Thanks for the feedback. 'NEVER TEST FOR EXACT EQUALITY BETWEEN FLOATING POINT NUMBERS.'
I am aware of that potential pitfall. Fortunately, only integer variables will be check for exact equality. The double-valued ratios will just be output of the universalFunction(data, equation script).
'I'd suggest you start rethinking what you need to do, and find a better way than using eval anyway. Eval is slow as hell. It will surely cause you problems down the line too.'
I totally agree. I have read @Stephen23's tutorial post for Matlab beginner. It has in-depth discussion about eval( ). I have indeed been thinking really hard about this problem. I could have taken a more conventional approach, writing many functions. But trying a very different way to tackle this problem is very seductive :-)
'For example, you might decide to reduce this to a set of generic expresssions. Now, write one function for each of those generic classes. Pass in your variables, get a result.'
Good advice. think I can divide them into two types: logical equality comparison and numeric calculation.
'In the case where a ratio is involved, then you will probably need to apply a tolerance on the result.'
Good advice.
Paul
on 2 Jul 2023
What's the advantage of entering everything as a string and then using str2func, as opposed to storing the functions directly in a cell array?
C = ["@(x, y, z) x-y==z"; "@(x, y) x/y"]
C = 2×1 string array
"@(x, y, z) x-y==z"
"@(x, y) x/y"
foo = str2func(C(1));
foo(3,2,1)
ans = logical
1
goo = str2func(C(2));
goo(4, 5)
ans = 0.8000
clear
C = {@(x,y,z) x - y == z; @(x,y) x/y;}
C = 2×1 cell array
{@(x,y,z)x-y==z}
{ @(x,y)x/y}
C{1}(3,2,1)
ans = logical
1
C{2}(4,5)
ans = 0.8000
Or, use a struct and then name the functions for clarity?
clear
C.foo = @(x,y,z) x - y == z;
C.goo = @(x,y) x/y;
C.foo(3,2,1)
ans = logical
1
C.goo(4,5)
ans = 0.8000
Simon
on 2 Jul 2023
Edited: Simon
on 2 Jul 2023
@Paul 'What's the advantage of entering everything as a string and then using str2func, as opposed to storing the functions directly in a cell array?'
I was trying out solutions generously suggested to me here. One advantage I could think of is to turn it into a table so that I can store 'cooments' in a new column.
'Or, use a struct and then name the functions for clarity?'
Naming function or variable is the biggest thing that slow my coding down significantly. I have an uncontrolable habit that I change names spontaneously.
I didn't know structure can be used in such a versatile way. It's wonderful to have learned that. Thanks!
Stephen23
on 2 Jul 2023
"What's the advantage of entering everything as a string and then using str2func, as opposed to storing the functions directly in a cell array?"
Advantage: the "equations" can be dynamically defined/created, but still offer the efficiency of calling function handles.
If the "equations" do not need to be dynamically created then simple (anonymous) function handles would be better.
Paul
on 2 Jul 2023
Comments can be stored using either the cell array or struct, if a cell array or struct with named fields happen to be the way to go.
C{1,1} = @(x,y,z) x - y == z;
C{1,2} = "this is the foo function";
C
C = 1×2 cell array
{@(x,y,z)x-y==z} {["this is the foo function"]}
% or
S.foo.eqn = @(x,y,z) x - y == z;
S.foo.comment = "this is the foo function";
S.foo
ans = struct with fields:
eqn: @(x,y,z)x-y==z
comment: "this is the foo function"
Answers (0)
See Also
Categories
Find more on Performance and Memory in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)