How to write one universal function to evaluate many equations?
6 次查看(过去 30 天)
显示 更早的评论
Simon
2023-7-2
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 个评论
Simon
2023-7-2
编辑:Simon
2023-7-2
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
2023-7-2
编辑:Stephen23
2023-7-2
"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
2023-7-2
编辑:Simon
2023-7-2
@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
2023-7-2
编辑:John D'Errico
2023-7-2
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
2023-7-2
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
2023-7-2
@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
2023-7-2
编辑:Simon
2023-7-2
@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
2023-7-2
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
2023-7-2
编辑:Simon
2023-7-2
@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
2023-7-2
"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
2023-7-2
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"
回答(0 个)
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Performance and Memory 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!发生错误
由于页面发生更改,无法完成操作。请重新加载页面以查看其更新后的状态。
您也可以从以下列表中选择网站:
如何获得最佳网站性能
选择中国网站(中文或英文)以获得最佳网站性能。其他 MathWorks 国家/地区网站并未针对您所在位置的访问进行优化。
美洲
- América Latina (Español)
- Canada (English)
- United States (English)
欧洲
- 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)
亚太
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)