Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Piecewise functions in the Octave symbolic package?

Tags:

octave

Unlike Matlab, Octave Symbolic has no piecewise function. Is there a work around? I would like to do something like this:

syms x
y = piecewise(x0, 1)

Relatedly, how does one get pieces of a piecewise function? I ran the following:

>> int (exp(-a*x), x, 0, t)

And got the following correct answer displayed and stored in a variable:

                                                                                  
      t      for a = 0

       -a*t
  1   e
  - - -----  otherwise
  a     a

But now I would like to access the "otherwise" part of the answer so I can factor it. How do I do that?

(Yes, I can factor it in my head, but I am practicing for when more complicated expressions come along. I am also only really looking for an approach using symbolic expressions -- even though in any single case numerics may work fine, I want to understand the symbolic approach.)

Thanks!

like image 434
forkandwait Avatar asked Jul 01 '17 04:07

forkandwait


1 Answers

Matlab's piecewise function seems to be fairly new (introduced in 2016b), but it basically just looks like a glorified ternary operator. Unfortunately I don't have 2016 to check if it performs any checks on the inputs or not, but in general you can recreate a 'ternary' operator in octave by indexing into a cell using logical indexing. E.g.

{@() return_A(), @() return_B(), @() return_default()}([test1, test2, true]){1}()

Explanation:

  • Step 1: You put all the values of interest in a cell array. Wrap them in function handles if you want to prevent them being evaluated at the time of parsing (e.g. if you wanted the output of the ternary operator to be to produce an error)
  • Step 2: Index this cell array using logical indexing, where at each index you perform a logical test
  • Step 3: If you need a 'default' case, use a 'true' test for the last element.
  • Step 4: From the cell (sub)array that results from above, select the first element and 'run' the resulting function handle. Selecting the first element has the effect that if more than one tests succeed, you only pick the first result; given the 'default' test will always succeed, this also makes sure that this is not picked unless it's the first and only test that succeeds (which it does so by default).

Here are the above steps implemented into a function (appropriate sanity checks omitted here for brevity), following the same syntax as matlab's piecewise:

function Out = piecewise (varargin)
  Conditions = varargin(1:2:end);    % Select all 'odd' inputs
  Values     = varargin(2:2:end);    % Select all 'even' inputs
  N          = length (Conditions);
  if length (Values) ~= N            % 'default' case has been provided
    Values{end+1} = Conditions{end}; % move default return-value to 'Values'
    Conditions{end} = true;          % replace final (ie. default) test with true
  end

  % Wrap return-values into function-handles
  ValFuncs = cell (1, N);
  for n = 1 : N; ValFuncs{n} = @() Values{n}; end

  % Grab funhandle for first successful test and call it to return its value
  Out = ValFuncs([Conditions{:}]){1}();
end

Example use:

>> syms x t;
>> F = @(a) piecewise(a == 0, t, (1/a)*exp(-a*t)/a);

>> F(0)
ans = (sym) t

>> F(3)
ans = (sym)

   -3⋅t
  ℯ
  ─────
    9
like image 177
Tasos Papastylianou Avatar answered Sep 17 '22 13:09

Tasos Papastylianou