I am new to object oriented programming. After much emphasis, I finally managed to define my own class of objects in the Matlab 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 point out that there is no need to know muPad to help with this problem. I think that anyone with relevant OOP experience can better understand this problem.
I will start with a little background. My class is called Bx. Its objects have two different properties: n and k such that n => k => 0. Accordingly, a certain object in "Bx" may 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 expression class called "DOM_EXPR", which is a superclass of subtypes of "_mult", "_plus", etc., for example. a + b will be of type "_plus", a * b will be of type "_mult", etc.
One of the operations that I defined in my class is multiplication. The rule is this:
Bx(a, b) * Bx(c, d) = binomial(a, c) * binomial(b, d) / binomial(a+c, b+d) * Bx(a+c, b+d)
Now this works fine in my code if one of the two objects to be multiplied belongs to the class "Bx". For instance:
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 problem arises as follows. Each time I multiply two objects of class "Bx" together, then the output will belong to another class called "DOM_EXPR" and enter "_mult". The above results are a good example. It makes sense; 3/5 * Bx (6, 3) - an expression consisting 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 by pure "Bx", for example:
a:=6*Bx(5,4); => nb type is "_mult" b:=Bx(4,3); => nb type is "Bx" c:=a*b
then I get the output: (10 * Bx (9, 7)) / 3, as expected. This is because in the definition of the _mult operation for the class "Bx" I determined how the objects "Bx" should work when multiplied by objects of the type "_mult" "DOM_EXPR".
However, sometimes a situation may arise when both Bx objects appear as part of the DOM_EXPR object. Example below:
a:=6*Bx(5,4); => nb type is "_mult" b:=3*Bx(4,3); => nb type is "_mult" c:=a*b
Now the result is as follows: (3 * Bx (4, 3)) * (6 * Bx (5, 4))
This is not what I want. I want muPad to evaluate this expression. If I took all the operands of the arguments and multiplied them along 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 to do muPad when multiplying a and b above.
I would be very interested in understanding how I can fix my code in order to behave correctly. I'm not necessarily looking for syntax, but maybe more for how you, an experienced OOP programmer, can implement what I am trying to do and how it is different 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 pasted the full muPad code below. You can run it in matlab, just type mupadwelcome in the command window, open a new mupad notepad and paste the individual blocks of code into 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 do not define my own _mult and _power methods, muPad seems to do what I want when multiplying two multi objects containing "Bx", except, obviously, the actual multiplication of "Bx", see . image below.
