OOP: Change of class of object following operation - operations no longer as desired

477 views Asked by At

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).

Note that 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 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)

The issue arises as follows. Anytime I multiply two objects of the class "Bx" together, then the output will belong to a different class, called "DOM_EXPR" and type, "_mult". 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.

However, sometimes a situation might arise where both "Bx" objects appear as part of a "DOM_EXPR" object. 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 below.

mupad screenshot

0

There are 0 answers