*
-- multiply expressionsx * y * ...
computes the product of x
,
y
etc.
x * y * ... _mult(x, y...)
x, y, ... |
- | arithmetical expressions,
polynomials of type DOM_POLY , or sets |
an arithmetical expression, a polynomial, or a set.
x
, y
, ,
...
_invert
, _negate
, product
, ^
, /
, +
, -
, poly
, Pref::timesDot
x * y * ...
is equivalent to the function call
_mult(x, y, ...)
.Type::Numeric
are automatically
combined to a single number._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
.x/y
is internally represented as x
* (1/y)
= _mult(x, _power(y, -1))
. See _divide
for details._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 * ...
.
_mult()
returns the number 1.DOM_POLY
are multiplied by
*
, if they have the same indeterminates and the same
coefficient ring. Use multcoeffs
to multiply
polynomials with scalar factors.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.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
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:
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])
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 }
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:
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: