OOP in Matlab - What to do when the output is a different class following method?
2 ビュー (過去 30 日間)
古いコメントを表示
I am new to Object Oriented Programming. After a lot of stressing, I have finally managed to define my own class of objects in matlab's symbolic engine, muPad. The engine has its own language, the syntax of which is very logical and similar to matlab itself.
I would like to note that it isn't necessary to know muPad to assist with this problem. I think anyone with relevant OOP experience will be able to provide more insight into the issue.
I will start with a bit of background. My class is called Bx. Its objects have two distinct properties, n and k such that n => k => 0. A properly defined object in "Bx" might thus look like Bx(0, 0), or Bx(2, 2) or Bx(7, 2)... Each object in "Bx" is unique; if n1 = n2 and k1 = k2 this means that Bx(n1, k1) = Bx(n2, k2).
A quick note here that will be relevant later - muPad has a built-in expressions class called "DOM_EXPR" that is a superclass of the subtypes "_mult", "_plus", etc. e.g. a + b would be type "_plus", a * b would be type "_mult" etc.
One of the operations that I have defined on my class is multiplication. The rule is as follows:
Bx(a, b) * Bx(c, d) = binomial(a, c) * binomial(b, d) / binomial(a+c, b+d) * Bx(a+c, b+d)
This now works perfectly in my code, as long as at least one of the two objects being multiplied belongs to the class "Bx". For example:
Input: Bx(2, 1)*Bx(4, 2)
Output: (3*Bx(6, 3))/5
Input: 2*y*Bx(2, 1)*Bx(4, 2)^2
Output: ((4*y)/7)*Bx(10, 5)
Anytime I multiply an object of the class "Bx" with any other object (be it another "Bx", or a DOM_INT, or a DOM_IDENT, or any other class), then the output will belong to the class "DOM_EXPR" type "_mult", described above The above outputs are a good example. This makes sense; 3/5*Bx(6, 3) is an expression, composed of objects of the classes "DOM_RAT" and "Bx", (4*y)/7*Bx(10, 5) consists of "DOM_RAT", "DOM_IDENT" and "Bx".
If I multiply such an expression with a pure "Bx", e.g.:
a:=6*Bx(5,4); => n.b. type is "_mult"
b:=Bx(4,3); => n.b. type is "Bx"
c:=a*b
then I get the output: (10*Bx(9, 7))/3 as expected. This is because in the _mult operation definition for the class "Bx", I have defined how "Bx" objects should behave when multiplied with "_mult" type "DOM_EXPR" objects.
The issue arises as follows. Sometimes a situation might arise where "Bx" objects appear exclusively as part of "_mult" objects. An example below:
a:=6*Bx(5,4); => n.b. type is "_mult"
b:=3*Bx(4,3); => n.b. type is "_mult"
c:=a*b
Now the output looks like: (3*Bx(4, 3))*(6*Bx(5, 4))
This is not what I want. I want muPad to further evaluate this expression. If I took all the operands of the arguments and multiplied them together with the existing code, I would get:
Input: 6*Bx(5,4)*3*Bx(4,3)
Output: 10*Bx(9, 7)
This is correct and what I would like muPad to do when multiplying a and b above.
I would be much endebted for any insight into how I can correct my code to behave correctly. I am not necessarily looking for syntax, but perhaps more for how you, an seasoned OOP programmer, might implement what I am trying to do, and how it differs from what I am doing. Once I understand what is wrong with my approach, and how I can improve it, I can figure out the syntax myself.
I have pasted the full muPad code below. You can run it in matlab, just type mupadwelcome in the command window, open a new mupad notebook and paste the individual blocks of code in new lines.
Bx := newDomain("Bx"):
Bx::new := proc(n,k)
begin
//++++//
if args(0)<>2 then
error("There must be exactly two arguments")
end_if;
//----//
new(dom,n,k)
end_proc:
------------------------------------
Bx::print := proc(x)
begin
//++++//
"Bx(".expr2text(op(x,1),op(x,2)).")";
end_proc:
------------------------------------
Bx::_mult := proc(a,b)
local type1,type2,berns,c,berns1,c1,berns2,c2,n,k,ni,ki;
begin
//++++//
if select(args(),testtype,"_mult") = null()
then
lists := split(args(),testtype,Bx);
berns := [lists[1]];
c := _mult(lists[2]);
ni := [op(berns[1])][1];
ki := [op(berns[1])][2];
//----//
if nops(berns) >= 2 and [op(berns)][1] <> [op([op(berns)][1])][1]
then
delete berns[1];
coefficient:=1;
//
while nops(berns)>=1
do
n := op(berns[1],1);
k := op(berns[1],2);
prod := Bx(_plus(ni,n),_plus(ki,k));
coefficient := coefficient*binomial(n,k)*binomial(ni,ki)/binomial(_plus(n,ni),_plus(k,ki));
delete berns[1];
ni := op(prod,1);
ki := op(prod,2);
end_while;
//
c := _mult(coefficient,c);
case c
of 1 do Bx(ni,ki); break;
otherwise freeze(_mult)(c,dom(ni,ki));
end_case;
else
case c
of 1 do berns[1]; break;
otherwise freeze(_mult)(c,berns[1]);
end_case;
end_if;
//----//
//++++//
else
lists := split(args(),testtype,"_mult");
_mult(op(lists[1]),lists[2],lists[3])
end_if;
//++++//
end_proc:
------------------------------------
Bx::_power := proc(a,b)
local res;
begin
//++++//
case b
of 0 do 1; break;
of 1 do a; break;
otherwise
res:=a;
//----//
for i from 1 to b-1 do
res:=res*a;
end_for;
//----//
res;
end_case;
//++++//
end_proc:
a:=6*Bx(5,4)
b:=3*Bx(4,3)
6*Bx(5,4)*3*Bx(4,3)
Edit: Interestingly, if I don't define my own _mult and _power methods, muPad seems to do what I want when multiplying two "_mult" objects containing "Bx", except evidently the actual "Bx" multiplication, see the image in the link below.
0 件のコメント
採用された回答
Christopher Creutzig
2013 年 8 月 7 日
Happens to work for me, in 2013a, but I think that is not the point, as that is probably coincidental for this particular example.
The problem with the _mult method you defined is that when you overload a function like _mult in MuPAD, you're actually responsible for the full multiplication, not just that of two arguments. I.e., in your last call, Bx::_mult is called with four arguments: 6, Bx(5,4), 3, Bx(4,3). It has to handle that, since MuPAD doesn't know whether you even want things like commutativity with numbers.
Here's what I think the structure you'll want could look like:
Bx::mult2 := proc(a : Bx, b : Bx)
... multiply two Bx objects ...
end_proc:
Bx::multBx := proc() // multiply arbitrarily many Bx
local n, left, right;
begin
case args(0)
of 0 do return(1);
of 1 do return(args(1));
of 2 do return(Bx::mult2(args()));
otherwise
n := floor(args(0)/2); % split here
left := Bx::multBx(args(1..n));
right := Bs::multBx(args(n+1..args(0)));
return(Bx::mult2(left, right));
end_case;
end_proc:
Bx::_mult := proc()
local Bxes, others, dummy;
begin
[Bxes, others, dummy] := split([args()], testtype, Bx);
assert(dummy = []);
others := _mult(op(others));
Bxes := Bx::multBx(op(Bxes));
if others = 1 then
return(Bxes);
elif Bxes = 1 then % can this happen?
return(others);
else
return(hold(_mult)(Bxes, others));
end_if;
end_proc:
その他の回答 (0 件)
参考
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!