# `piecewise`

Domain of conditionally defined objects

MuPAD® notebooks will be removed in a future release. Use MATLAB® live scripts instead.

MATLAB live scripts support most MuPAD functionality, though there are some differences. For more information, see Convert MuPAD Notebooks to MATLAB Live Scripts.

## Syntax

```piecewise([`cond1`, `value1`], [`cond2`, `value2`], …, <[`Otherwise`, `valueN`]>, <`ExclusiveConditions`>)
```

## Description

`piecewise([cond1, value1], [cond2, value2], ...)` defines a conditional object that equals `value1` if `cond1` is provably true, `value2` if `cond2` is provably true, and so on. Typically, such objects define piecewise functions or express solutions based on a case analysis of the free parameters of the mathematical problem. See Example 1.

A pair `[condition, value]` is called a branch. If `condition` is provably false, then `piecewise` discards the entire branch. If `condition` is provably true, then `piecewise` returns the corresponding `value`. If neither condition in a piecewise object is provably true, `piecewise` returns an object of type `piecewise` that contains all branches, except for branches with provably false conditions.

If all conditions are provably false, or if you call `piecewise` without any branches, then `piecewise` returns `undefined`. See Example 1.

Conditions do not need to be exhaustive or exclusive. If conditions contain parameters, and you substitute values for the parameters, all conditions can become false. Also, several conditions can become true.

If several conditions are simultaneously true, `piecewise` returns the value from the first branch that contains the condition recognized as true. Ensure that all values corresponding to the true conditions have the same mathematical meaning. Do not rely on the system to recognize the first mathematically true condition as true. Alternatively, you can use the `ExclusiveConditions` option to fix the order of the branches.

```piecewise([cond1, value1], [cond2, value2], ..., [Otherwise, valueN])``` checks the conditions, and, if they are not satisfied, discards them and returns `valueN`. The `Otherwise` condition occurs in the last branch. It can occur only once. It remains unchanged as long as there are other branches, but it is treated as true when all other branches are discarded because their conditions are false. See Example 2.

The system checks the truth of the conditions for current values and properties of all involved identifiers each time it evaluates an object of type `piecewise`. Thus, it simplifies piecewise expressions under various different assumptions.

`piecewise` objects can be nested: both conditions and values can be `piecewise` objects themselves. `piecewise` automatically “flattens” such objects. For example, ```piecewise([conditionA, piecewise([conditionB, valueC])])``` becomes ```piecewise([conditionA and conditionB, valueC])```. See Example 3.

Arithmetical and set-theoretic operations work for `piecewise` objects, provided these operations are defined for all values contained in the branches. If `f` is such an operation and ```p1, p2, ...``` are `piecewise` objects, then ```f(p1, p2, ...)``` is the `piecewise` object consisting of all branches of the form ```[cond1 and cond2 and ..., f(value1, value2, ...)]```, where `[cond1, value1]` is a branch of `p1`, `[cond2, value2]` is a branch of `p2`, and so on. In other words, applying `f` commutes with any assignment to free parameters in the conditions. See Example 4.

`piecewise` objects can also be mixed with other objects in such operations. In such cases, if `p1` is not a `piecewise` object, the system treats it as a `piecewise` object with the only branch ```[TRUE, p1]```. See Example 5.

`diff`, `float`, `limit`, `int` and similar functions handle expressions involving `piecewise`. When you use a `piecewise` argument in unary operators and functions with one argument, the system maps the operator or function to the values in each branch. See Example 6, Example 7, and Example 8.

`piecewise` differs from the `if` and `case` branching statements. First, `piecewise` uses the property mechanism when deciding the truth of the conditions. Therefore, the result depends on the properties of the identifiers that appear in the conditions. Second, `piecewise` treats conditions mathematically, while `if` and `case` evaluate them syntactically. Third, `piecewise` internally sorts the branches. If conditions in several branches are true, `piecewise` can return any of these branches. See Example 9.

The `ExclusiveConditions` option fixes the order of branches in a piecewise expression. If the condition in the first branch returns `TRUE`, then `piecewise` returns the value from the first branch. If a true condition appears in any further branch, then `piecewise` returns the value from that branch and removes all subsequent branches. Thus, `piecewise` with `ExclusiveConditions` is very similar to an `if-elif-end_if` statement. Nevertheless, `piecewise` with `ExclusiveConditions` still takes into account assumptions on identifiers and treats conditions mathematically while `if-elif-end_if` treats them syntactically. See Example 10.

## Environment Interactions

`piecewise` takes into account properties of identifiers.

## Examples

### Example 1

Define this rectangular function `f`. Without additional information about the variable x, the system cannot evaluate the conditions to `TRUE` or `FALSE`. Therefore, it returns the `piecewise` object.

`f := x -> piecewise([x < 0 or x > 1, 0], [x >= 0 and x <= 1, 1])`

Call the function `f` with the following arguments. Every time you call this piecewise function, the system checks the conditions in its branches and evaluates the function.

`f(0), f(2), f(I)`

### Example 2

Create this piecewise function using the syntax that includes `Otherwise`:

`pw:= piecewise([x > 0 and x < 1, 1], [Otherwise, 0])`

Evaluate `pw` for these three values:

```pw | x = 1/2; pw | x = 2; pw | x = I;```

For further computations, delete the identifier `pw`:

`delete pw:`

### Example 3

Create this nested piecewise expression. MuPAD® flattens nested `piecewise` objects.

```p1 := piecewise([a > 0, a^2], [a <= 0, -a^2]): piecewise([b > 0, a + b], [b = 0, p1 + b], [b < 0, a + b])```

### Example 4

Find the sum of these piecewise functions. You can perform most operations on piecewise functions the same way as you would on ordinary arithmetical expressions. The result of an arithmetical operation is only defined at the points where all of the arguments are defined:

`piecewise([x > 0, 1], [x < -3, x^2]) + piecewise([x < 2, x])`

### Example 5

Solve this equation. The solver returns the result as a piecewise set:

`S := solve(a*x = 0, x)`

You can use set-theoretic operations work for such sets. For example, find the intersection of this set and the interval ```(3, 5)```:

`S intersect Dom::Interval(3, 5)`

### Example 6

Many unary functions are overloaded for `piecewise` by mapping them to the objects in all branches of the input:

```f := piecewise([x >= 0, arcsin(x)], [x < 0, arccos(x)]): sin(f)```

### Example 7

Find the limit of this piecewise function:

```limit(piecewise([a > 0, x],[a < 0 and x > 1, 1/x], [a < 0 and x <= 1, -x]), x = infinity)```

### Example 8

Find the integral of this piecewise function:

`int(piecewise([x < 0, x^2], [x > 0, x^3]), x = -1..1)`

### Example 9

Create this piecewise function. Here, `piecewise` cannot determine if any branch is true or false. To do that, `piecewise` needs additional information about the identifier `a`.

`p1 := piecewise([a = 0, 0], [a <> 0, 1/a])`

Create a similar structure by using `if-then-else`. The `if-then-else` structure evaluates the conditions syntactically. Here, `a = 0` is technically false because the identifier `a` and the integer `0` are different objects.

`p2 := (if a = 0 then 0 else 1/a end)`

`piecewise` takes properties of identifiers into account:

`p1 := piecewise([a + b = 0, 0], [Otherwise, 1/a]) assuming a + b = 0`

`if-then-else` does not:

`p2 := (if a + b = 0 then 0 else 1/a end) assuming a + b = 0`

For further computations, delete identifiers `a`, `b`, `p1`, and `p2`:

`delete a, b, p1, p2:`

### Example 10

Create this piecewise expression:

`p := piecewise([x > 0, 1], [y > 0, 2])`

Evaluate the expression at `y = 1`:

`p | y = 1`

Now, create the piecewise expression with the same branches, but this time use `ExclusiveConditions` to fix the order of the branches. When you use this option, any branch can be true only if the previous branches are false.

`pE := piecewise([x > 0, x], [y > 0, y], ExclusiveConditions)`

Evaluate the expression at `y = 1`:

`pE | y = 1`

When you use `ExclusiveConditions`, `piecewise` acts the same way as an `if-then-else` statement, but does not ignore properties of identifiers. For example, set the assumption that `x = 0`:

`assume(x = 0)`

The `piecewise` function call returns 0 because it uses the assumption on identifier `x`:

`p := piecewise([x = 0, x], [Otherwise, 1/x^2])`

The corresponding `if-then-else` statement ignores the assumption, and, therefore, returns `1/x^2`:

`pIf := (if x = 0 then x else 1/x^2 end)`

For further computations, delete identifiers `p`, `pE`, `x`, and `pIf`:

`delete p, pE, x, pIf:`

### Example 11

Find a set of accumulation points of this piecewise function by calling `limit` with the `Intervals` option:

```limit(piecewise([a > 0, sin(x)], [a < 0 and x > 1, 1/x], [a < 0 and x <= 1, -x]), x = infinity, Intervals)```

### Example 12

Rewrite the `sign` function in terms of a `piecewise` object:

`f := rewrite(sign(x), piecewise)`

### Example 13

Create this `piecewise` object:

`f := piecewise([x > 0, 1], [x < -3, x^2])`

Extract a particular condition or object:

`piecewise::condition(f, 1), piecewise::expression(f, 2)`

The index operator has the same meaning as `piecewise::expression` and can be typed faster:

`f[2]`

The `piecewise::branch` function extracts whole branches:

`piecewise::branch(f, 1)`

You can form another `piecewise` object from the branches for which the condition satisfies a given selection criterion, or split the input into two `piecewise` objects, as the system functions `select` and `split` do it for lists:

`piecewise::selectConditions(f, has, 0)`

`piecewise::splitConditions(f, has, 0)`

You can also create a copy of `f` with some branches added or removed:

`piecewise::remove(f, 1)`

`piecewise::insert(f, [x > -3 and x < 0, sin(x)])`

## Parameters

 `cond1, cond2, …` Boolean constants, or expressions representing logical formulas `object1, object2, …` Arbitrary objects `Otherwise` Identifier that specifies the last condition. This condition is always treated as a true condition.

## Options

 `ExclusiveConditions` The `ExclusiveConditions` option fixes the order of branches in a piecewise expression. This option causes `piecewise` to automatically remove branches with false conditions. Thus, `piecewise` with `ExclusiveConditions` is almost equivalent to an `if-elif-end_if` statement, except that `piecewise` takes into account assumptions on identifiers. For example, if the condition in the first branch returns `TRUE`, then `piecewise` returns the expression from the first branch. If a true condition appears in any further branch, then `piecewise` returns the expression from that branch and removes all subsequent branches.

## Methods

expand all

#### Mathematical Methods

`_in(p, S)`

`contains(p, a)`

This method overloads the function `contains`. The values in all branches must be valid first arguments for `contains`.

`diff(p, <x, …>)`

If no variables are given, `p` is returned.

```discont(p, x, <F>)```

```discont(p, x = a .. b, <F>)```

The values in all branches of `p` must be arithmetical expressions.

The optional third parameter has the same meaning as for the function `discont`.

As for the function `discont`, only discontinuities in the given interval `[a,b]` are returned when calling `piecewise(p, x = a..b)`.

`disregardPoints(p)`

`expand(p)`

`factor(p)`

`getElement(p)`

The result is `FAIL` if no such common element is found.

This method overloads the function `solvelib::getElement`.

`has(p, a)`

```int(p, x, <r>)```

If a range `a..b` is given, this method computes the definite integral of `p` when `x` runs through that range.

`ilaplace(p, x, t)`

`isFinite(p)`

This method overloads `solvelib::isFinite`.

`laplace(p, x, t)`

```limit(p, x, <Left | Right | Real>, <Intervals>, <NoWarning>)```

```limit(p, x = x0, <Left | Right | Real>, <Intervals>, <NoWarning>)```

When called with the `Intervals` option, the method returns the set of accumulation points of a function.

If the method cannot find the function limit and cannot prove the limit does not exist, the function call returns an unevaluated `limit` function.

If the limit of a function does not exist, the method returns the special value `undefined`.

This method overloads the function `limit`.

`normal(p)`

`partfrac(p)`

`restrict(p, C)`

`set2expr(p, x)`

The objects in all branches of `p` must represent sets.

This method overloads the system function `_in`.

`simplify(p)`

```solve(p, x, <option1, option2, …>)```

For each branch `[condition, value]` of `p`, with `value` being an equation or inequality, the method determines the set of all values `x` such that both `condition` and `value` become true mathematically, and returns the union of all obtained sets. The return value can be a conditionally defined set.

This method overloads the function `solve`. See the corresponding help page for a description of the available options and an overview of the types of sets that can be returned.

`solveConditions(p, x)`

`Union(p, x, indexset)`

The values in all branches of `p` must represent sets.

For each branch `[condition, value]` of `p`, this method does the following. It substitutes for `x` in `value` all values from `indexset` satisfying `condition` and takes the union over all obtained sets. Then it returns the union over the resulting sets for all branches.

This method overloads the function `solvelib::Union`.

#### Access Methods

`_concat(p, …)`

`branch(p, n)`

`op(p)`

`op(p, n)`

`op(p, n)` returns the `n`th branch of `p` as a list. If n = 0, then `piecewise` is returned.

`setBranch(p, i, b)`

`numberOfBranches(p)`

`condition(p, i)`

`setCondition(p, i, cond)`

`expression(p, i)`

Instead of `piecewise::expression(p, i)`, the index operator `p[i]` can be used synonymously.

`_index(p, i)`

`piecewise::expression` can be used synonymously.

`setExpression(p, i, a)`

`insert(p, b)`

`b` can either be a branch extracted from another conditionally defined object using `extop`, or a list `[condition, object]`.

See Example 13.

```extmap(p, f, <a, …>)```

```mapConditions(p, f, <a, …>)```

```map(p, f, <a, …>)```

`map(p, f)` is equivalent to ```piecewise::extmap(p, map, f)```.

`remove(p, i)`

`splitBranch(p, i, newcondition)`

```selectConditions(p, f, <a, …>)```

For every condition in `p`, ```f(condition a, …)``` must return a Boolean  constant.

If none of the conditions satisfies the selection criterion, `undefined` is returned.

```selectExpressions(p, f, <a, …>)```

For every value in `p`, ```f(value a, …)``` must return a Boolean constant.

If none of the objects satisfies the selection criterion, `undefined` is returned.

```splitConditions(p, f, <a, …>)```

For every condition in `p`, ```f(condition a, …)``` must return a Boolean constant.

See Example 13.

`subs(p, s, …)`

This method overloads the function `subs`. The calling syntax is identical to that function. See the corresponding help page for a description of the various types that are allowed for `s`.

`zip(p1, p2, f)`

If we regard conditionally defined objects as functions from the set A of parameter values to a set B of objects, this method implements the canonical extension of the binary operation f on B to the binary operation g on the set BA of all functions from A to B via g(p1, p2)(a) = f(p1(a), p2(a)) for all a in A.

If only one of the first two arguments—`p1`, say—is of type `piecewise`, then each branch ```[condition, value]``` of `p1` is replaced by ```[condition, f(value, p2)]```.

If neither `p1` nor `p2` are of type `piecewise`, then ```piecewise::zip(p1, p2, f)``` returns `f(p1, p2)`.

## Algorithms

The operands of a `piecewise` object (the branches) are pairs consisting of a condition and the value valid under that condition.

Methods overloading system functions always assume that they have been called via overloading, and that there is some conditionally defined object among their arguments. All other methods do not assume that one of their arguments is of type `piecewise`. This simplifies the use of `piecewise`: it is always allowed to enter `p:=piecewise(...)` and to call some method of `piecewise` with `p` as an argument. You do not need to care about the special case where `p` is not of type `piecewise` because some condition in its definition is true or all conditions are false.