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))/5Input: 2*y*Bx(2, 1)*Bx(4, 2)^2Output: ((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.
Best Answer