## `*` -- multiply expressions

#### Introduction

`x * y * ...` computes the product of `x`, `y` etc.

#### Call(s)

x * y * ... `_mult(x, y...)`

#### Parameters

`x, y, ...` | - | arithmetical expressions, polynomials of type `DOM_POLY`, or sets

#### Returns

an arithmetical expression, a polynomial, or a set.

### Overloadable:

`x`, `y`, ``, `...`

#### Related Functions

`_invert`, `_negate`, `product`, `^`, `/`, `+`, `-`, `poly`, `Pref::timesDot`

#### Details

- `x * y * ...` is equivalent to the function call `_mult(x, y, ...)`.
- All terms that are numbers of type `Type::Numeric` are automatically combined to a single number.
- The terms of a symbolic product may be rearranged internally if no term belongs to a library domain that overloads `_mult`: on terms composed of kernel domains (numbers, identifiers, expressions etc.), multiplication is assumed to be commutative. Cf. example 1.

  Via overloading, the user can implement a non-commutative product for special domains.

- `_mult` accepts an arbitrary number of arguments. In conjunction with the sequence operator `$`, this function is the recommended tool for computing finite products. Cf. example 2. The function `product` may also serve for computing such products. However, `product` is designed for the computation of symbolic and infinite products. It is slower than `_mult`.
- The quotient `x/y` is internally represented as `x * (1/y)` = `_mult(x, _power(y, -1))`. See `_divide` for details.
- Many library domains overload `_mult` by an appropriate slot `"_mult"`. Products involving elements of library domains are processed as follows:

  A product `x * y * ...` is searched for elements of library domains from left to right. Let `z` be the first term that is not of one of the basic types provided by the kernel (numbers, expressions, etc.). If the domain `d` = `z::dom` = `domtype(z)` has a slot `"_mult"`, it is called in the form `d::_mult(x, y, ...)`. The result returned by `d::_mult` is the result of `x * y * ...`.

  Cf. examples 5 and 6.

- `_mult()` returns the number 1.
- Polynomials of type `DOM_POLY` are multiplied by `*`, if they have the same indeterminates and the same coefficient ring. Use `multcoeffs` to multiply polynomials with scalar factors.
- For finite sets `X`, `Y`, the product `X * Y` is the set {x * y; x in X; y in Y}.
- `_mult` is a function of the system kernel.

#### Example 1

Numerical terms are simplified automatically:

    >> 3 * x * y * (1/18) * sin(4) * 4

                                   2 x y sin(4)
                                   ------------
                                        3

The ordering of the terms of a product is not necessarily the same as on input:

    >> x * y * 3 * z * a * b * c

                                   3 a b c x y z

Internally, this product is a symbolic call of `_mult`:

    >> op(%, 0), type(%)

                                  _mult, "_mult"

Note that the screen output does not necessarily reflect the internal order of the terms in a product:

    >> op(%2)

                                a, b, c, x, y, z, 3

In particular, a numerical factor is internally stored as the last operand. On the screen, a numerical factor is displayed in front of the remaining terms:

    >> 3 * x * y * 4

                                      12 x y

    >> op(%)

                                     x, y, 12

#### Example 2

The functional equivalent `_mult` of the operator `*` is a handy tool for computing finite products. In the following, the terms are generated via the sequence operator `$`:

    >> _mult(i $ i = 1..20)

                                2432902008176640000

E.g., it is easy to multiply all elements in a set:

    >> S := {a, b, 1, 2, 27}: _mult(op(S))

                                      54 a b

The following command ``zips'' two lists by multiplying corresponding elements:

    >> L1 := [1, 2, 3]: L2 := [a, b, c]: zip(L1, L2, _mult)

                                   [a, 2 b, 3 c]

    >> delete S, L1, L2:

#### Example 3

Polynomials of type `DOM_POLY` are multiplied by `*`, if they have the same indeterminates and the same coefficient ring:

    >> poly(x^2 + 1, [x]) * poly(x^2 + x - 1, [x])

                                  4    3
                            poly(x  + x  + x - 1, [x])

Symbolic products are returned if the indeterminates or the coefficient rings do not match:

    >> poly(x, [x]) * poly(x, [x, y])

                           poly(x, [x]) poly(x, [x, y])

    >> poly(x, [x]) * poly(x, [x], Dom::Integer)

                      poly(x, [x]) poly(x, [x], Dom::Integer)

Multiplication of polynomials with scalar factors cannot be achieved with `*`:

    >> 2 * y * poly(x, [x])

                                 2 poly(x, [x]) y

Use `multcoeffs` instead:

    >> multcoeffs(poly(x^2 - 2, [x]), 2*y)

                                         2
                             poly((2 y) x  - 4 y, [x])

#### Example 4

For finite sets `X`, `Y`, the product `X * Y` is the set {x * y; x in X; y in Y}:

    >> {a, b, c} * {1, 2}

                             {a, b, c, 2 a, 2 b, 2 c}

    >> 2 * {a, b, c} * c

                                                 2
                               {2 a c, 2 b c, 2 c }

#### Example 5

Various library domains such as matrix domains overload `_mult`. The multiplication is not commutative:

    >> x := Dom::Matrix(Dom::Integer)([[1, 2], [3, 4]]):
       y := Dom::Matrix(Dom::Rational)([[10, 11], [12, 13]]):
       x * y, y * x

                            +-        -+  +-        -+
                            |  34, 37  |  |  43, 64  |
                            |          |, |          |
                            |  78, 85  |  |  51, 76  |
                            +-        -+  +-        -+

If the terms in `x * y` are of different type, the first term `x` tries to convert `y` to the data type of `x`. If successful, the product is of the same type as `x`. In the previous example, `x` and `y` have different types (both are matrices, but the component domains differ). Hence `x * y` and `y * x` have different types that is inherited from the first term:

    >> domtype(x * y), domtype(y * x)

               Dom::Matrix(Dom::Integer), Dom::Matrix(Dom::Rational)

If `x` does not succeed to convert `y`, then `y` tries to convert `x`. In the following call, the component `27/2` cannot be converted to an integer. Consequently, in `x * y`, the term `y` converts `x` and produces a result that coincides with the domain type of `y`:

    >> y := Dom::Matrix(Dom::Rational)([[10, 11], [12, 27/2]]):
       x * y, y * x

                           +-        -+  +-           -+
                           |  34, 38  |  |    43,  64  |
                           |          |, |             |
                           |  78, 87  |  |  105/2, 78  |
                           +-        -+  +-           -+

    >> domtype(x * y), domtype(y * x)

              Dom::Matrix(Dom::Rational), Dom::Matrix(Dom::Rational)

    >> delete x, y:

#### Example 6

This example demonstrates how to implement a slot `"_mult"` for a domain. The following domain `myString` is to represent character strings. Via overloading of `_mult`, integer multiples of such strings should produce the concatenation of an appropriate number of copies of the string.

The `"new"` method uses `expr2text` to convert any MuPAD object to a string. This string is the internal representation of elements of `myString`. The `"print"` method turns this string into the screen output:

    >> myString := newDomain("myString"):
       myString::new := proc(x)
       begin
         if args(0) = 0 then x := "": end_if;
         case domtype(x)
           of myString do return(x);
           of DOM_STRING do return(new(dom, x));
           otherwise return(new(dom, expr2text(x)));
         end_case
       end_proc:
       myString::print := x -> extop(x, 1):

Without a `"_mult"` method, the system function `_mult` handles elements of this domain like any symbolic object:

    >> y := myString(y): z := myString(z): 4 * x * y * z * 3/2

                                      6 x y z

Now, we implement the `"_mult"` method. It uses `split` to pick out all integer terms in its argument list and multiplies them. The result is an integer `n`. If there is exactly one other term left (this must be a string of type `myString`), it is copied `n` times. The concatenation of the copies is returned:

    >> myString::_mult:= proc()
       local Arguments, intfactors, others, dummy, n;
       begin
         userinfo(10, "myString::_mult called with the arguments:",
                  args());
         Arguments := [args()];
         // split the argument list into integers and other factors:
         [intfactors, others, dummy] :=
             split(Arguments, testtype, DOM_INT);
         // multiply all integer factors:
         n := _mult(op(intfactors));
         if nops(others) <> 1 then
            return(FAIL)
         end_if;
         myString::new(_concat(extop(others[1], 1) $ n))
       end_proc:

       setuserinfo(myString::_mult, 10):

Now, integer multiples of `myString` objects can be constructed via the `*` operator:

    >> 2 * myString("string") * 3

          Info: myString::_mult called with the arguments:, 2, string, 3

                       stringstringstringstringstringstring

Only products of integers and `myString` objects are allowed:

    >> 3/2 * myString("a ") * myString("string")

          Info: myString::_mult called with the arguments:, 3/2, a , str\
          ing

                                       FAIL

    >> delete myString, y, z:

#### Changes

- no changes

Do you have questions or comments?
Copyright © SciFace Software GmbH & Co. KG 2000