changeset 22901:4c56f3ffec04

Add functions ode15i and ode15s * libinterp/dldfcn/__ode15__.cc: Add oct-file backend for m-files ode15i.m and ode15s.m. * scripts/ode/ode15i.m: Add wrapper function ode15i.m. * scripts/ode/ode15s.m: Add wrapper function ode15s.m. * scripts/ode/private/check_default_input.m: Add private function to check default input of ode15i and ode15s. * libinterp/dldfcn/module-files: Add __ode15__.cc and its flags.
author Francesco Faccio <francesco.faccio@mail.polimi.it>
date Tue, 23 Aug 2016 03:19:11 +0200
parents ee1c77705fcd
children 284bbb0328f2
files libinterp/dldfcn/__ode15__.cc libinterp/dldfcn/module-files scripts/ode/decic.m scripts/ode/ode15i.m scripts/ode/ode15s.m scripts/ode/private/check_default_input.m
diffstat 6 files changed, 2617 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/dldfcn/__ode15__.cc	Tue Aug 23 03:19:11 2016 +0200
@@ -0,0 +1,1321 @@
+/*
+
+Copyright (C) 2016 Francesco Faccio <francesco.faccio@mail.polimi.it>
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#if defined (HAVE_IDA_IDA_H)
+#include <ida/ida.h>
+#include <ida/ida_dense.h>
+#include <ida/ida_klu.h>
+#include <sundials/sundials_sparse.h>
+#endif
+
+#if defined (HAVE_NVECTOR_NVECTOR_SERIAL_H)
+#include <nvector/nvector_serial.h>
+#endif
+
+
+#include <oct.h>
+#include <parse.h>
+#include <time.h> 
+
+#include "defun-dld.h"
+#include "iostream"
+#include "error.h"
+#include "ov.h"
+#include "ov-struct.h"
+#include "errwarn.h"
+
+#include "algorithm"
+#include "iterator"
+
+
+#if defined (HAVE_SUNDIALS)
+
+namespace octave
+{
+  class IDA
+  {
+  public:
+
+    typedef
+    ColumnVector (*DAERHSFuncIDA) (const ColumnVector& x,
+                                   const ColumnVector& xdot,
+                                   realtype t, octave_function *idaf);
+
+    typedef
+    Matrix (*DAEJacFuncDense) (const ColumnVector& x,
+                               const ColumnVector& xdot, realtype t,
+                               realtype cj, octave_function *idaj);
+
+    typedef
+    SparseMatrix (*DAEJacFuncSparse) (const ColumnVector& x,
+                                      const ColumnVector& xdot,
+                                      realtype t, realtype cj,
+                                      octave_function *idaj);
+
+    typedef
+    Matrix (*DAEJacCellDense) (Matrix *dfdy, Matrix *dfdyp,
+                               realtype cj);
+
+    typedef
+    SparseMatrix (*DAEJacCellSparse) (SparseMatrix *dfdy,
+                                      SparseMatrix *dfdyp, realtype cj);
+
+    //Default 
+    IDA (void)
+      : t0 (0.0), y0 (), yp0 (), havejac (false), havejacfun (false),
+        havejacsparse (false), mem (NULL), num (), ida_fun (NULL),
+        ida_jac (NULL), dfdy (NULL), dfdyp (NULL), spdfdy (NULL),
+        spdfdyp (NULL), fun (0), jacfun (NULL), jacspfun (0),
+        jacdcell (0), jacspcell (0)
+    { };
+
+
+    IDA (realtype t, ColumnVector y, ColumnVector yp,
+         octave_function *ida_fcn, DAERHSFuncIDA daefun)
+      : t0 (t), y0 (y), yp0 (yp), havejac (false), havejacfun (false),
+        havejacsparse (false), mem (NULL), num (), ida_fun (ida_fcn),
+        ida_jac (NULL), dfdy (NULL), dfdyp (NULL), spdfdy (NULL),
+        spdfdyp (NULL), fun (daefun), jacfun (NULL), jacspfun (0),
+        jacdcell (0), jacspcell (0)
+    { };
+
+
+    ~IDA (void) { IDAFree (&mem); } 
+  
+    IDA&
+    set_jacobian (octave_function *jac, DAEJacFuncDense j)
+    {
+      jacfun = j;
+      ida_jac = jac;
+      havejac = true;
+      havejacfun = true;
+      havejacsparse = false;
+      return *this;
+    }
+  
+    IDA&
+    set_jacobian (octave_function *jac, DAEJacFuncSparse j)
+    {
+      jacspfun = j;
+      ida_jac = jac;
+      havejac = true;
+      havejacfun = true;
+      havejacsparse = true;
+      return *this;
+    }
+
+    IDA&
+    set_jacobian (Matrix *dy, Matrix *dyp, DAEJacCellDense j)
+    {
+      jacdcell = j;
+      dfdy = dy;
+      dfdyp = dyp;
+      havejac = true;
+      havejacfun = false;
+      havejacsparse = false;
+      return *this;
+    }
+
+    IDA&
+    set_jacobian (SparseMatrix *dy, SparseMatrix *dyp,
+                  DAEJacCellSparse j)
+    {
+      jacspcell = j;
+      spdfdy = dy;
+      spdfdyp = dyp;
+      havejac = true;
+      havejacfun = false;
+      havejacsparse = true;
+      return *this;
+    }
+ 
+    void
+    set_userdata (void);
+
+    void
+    initialize (void);
+
+    static ColumnVector
+    NVecToCol (N_Vector& v, long int n);
+
+    static N_Vector
+    ColToNVec (const ColumnVector& data, long int n); 
+
+    void
+    set_up (void);
+
+    void
+    set_tolerance (ColumnVector& abstol, realtype reltol); 
+
+    void
+    set_tolerance (realtype abstol, realtype reltol); 
+
+    static int
+    resfun (realtype t, N_Vector yy, N_Vector yyp,
+            N_Vector rr, void *user_data);
+
+    void
+    resfun_impl (realtype t, N_Vector& yy,
+                 N_Vector& yyp, N_Vector& rr);
+
+    static int
+    jacdense (long int Neq, realtype t,  realtype cj, 
+              N_Vector yy, N_Vector yyp, N_Vector resvec,
+              DlsMat JJ, void *user_data, N_Vector tempv1,
+              N_Vector tempv2, N_Vector tempv3)
+    {
+      IDA *self =
+        static_cast <IDA *> (user_data);
+
+      self -> jacdense_impl (Neq, t, cj, yy, yyp, JJ);
+      return 0;
+    }
+
+    void
+    jacdense_impl (long int Neq, realtype t, realtype cj,
+                   N_Vector& yy, N_Vector& yyp, DlsMat& JJ);
+
+    static int
+    jacsparse (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
+               N_Vector r, SlsMat Jac, void *user_data, N_Vector tmp1,
+               N_Vector tmp2, N_Vector tmp3)
+    {
+      IDA *self =
+        static_cast <IDA *> (user_data);
+
+      self -> jacsparse_impl (t, cj, yy, yyp, Jac);
+      return 0;
+    }
+
+    void
+    jacsparse_impl (realtype t, realtype cj, N_Vector& yy,
+                    N_Vector& yyp, SlsMat& Jac);
+
+    void
+    set_maxstep (realtype maxstep); 
+
+    void
+    set_initialstep (realtype initialstep); 
+
+    bool
+    interpolate (int& cont, Matrix& output, ColumnVector& tout,
+                 int refine, realtype tend, bool haveoutputfcn,
+                 bool haveoutputsel, octave_function *output_fcn,
+                 ColumnVector& outputsel, bool haveeventfunction,
+                 octave_function * event_fcn, ColumnVector& te,
+                 Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
+                 ColumnVector& oldisterminal, ColumnVector& olddir,
+                 int& temp, ColumnVector& yold);
+
+    bool
+    outputfun (octave_function *output_fcn, bool haveoutputsel, 
+               const ColumnVector& output, realtype tout, realtype tend,
+               ColumnVector& outputsel, std::string flag);
+
+
+    bool
+    event (octave_function *event_fcn,
+           ColumnVector& te, Matrix& ye, ColumnVector& ie,
+           realtype tsol, const ColumnVector& y, std::string flag,
+           const ColumnVector& yp, ColumnVector& oldval,
+           ColumnVector& oldisterminal, ColumnVector& olddir,
+           int cont, int& temp, realtype told, ColumnVector& yold);
+
+    void
+    set_maxorder (int maxorder);
+
+    octave_value_list
+    integrate (const int numt, const ColumnVector& tt,
+               const ColumnVector& y0, const ColumnVector& yp0,
+               const int refine, bool haverefine, bool haveoutputfcn,
+               octave_function *output_fcn, bool haveoutputsel,
+               ColumnVector& outputsel, bool haveeventfunction,
+               octave_function *event_fcn);
+
+    void
+    print_stat (void);
+  
+  private:
+
+    realtype t0;
+    ColumnVector y0;
+    ColumnVector yp0;
+    bool havejac;
+    bool havejacfun;
+    bool havejacsparse;
+    void *mem;
+    int num;
+    octave_function *ida_fun;
+    octave_function *ida_jac;
+    Matrix *dfdy;
+    Matrix *dfdyp;
+    SparseMatrix *spdfdy;
+    SparseMatrix *spdfdyp;
+    DAERHSFuncIDA fun;
+    DAEJacFuncDense jacfun;
+    DAEJacFuncSparse jacspfun;
+    DAEJacCellDense jacdcell;
+    DAEJacCellSparse jacspcell;
+
+  };
+
+  int
+  IDA::resfun (realtype t, N_Vector yy, N_Vector yyp, N_Vector rr,
+               void *user_data)
+  { 
+    IDA *self =
+      static_cast <IDA *> (user_data);
+
+    self -> resfun_impl (t, yy, yyp, rr);
+    return 0;
+  }
+
+  void
+  IDA::resfun_impl (realtype t, N_Vector& yy,
+                    N_Vector& yyp, N_Vector& rr)
+  {
+    BEGIN_INTERRUPT_WITH_EXCEPTIONS;
+
+    ColumnVector y =
+      IDA::NVecToCol (yy, num);
+
+    ColumnVector yp =
+      IDA::NVecToCol (yyp, num);
+
+    ColumnVector res =
+      (*fun) (y, yp, t, ida_fun);  
+    
+    realtype *puntrr = 
+      NV_DATA_S (rr);
+
+    for (octave_idx_type i = 0; i < num; i++)
+      puntrr [i] = res (i);
+
+    END_INTERRUPT_WITH_EXCEPTIONS;
+  }
+
+  void
+  IDA::set_up (void)
+  {
+    if (havejacsparse)
+      {
+        int flag =
+          IDAKLU (mem, num, num*num);
+        if (flag != 0)
+          {
+            error ("IDAKLU solver not initialized");
+          }
+        flag = IDASlsSetSparseJacFn (mem, IDA::jacsparse);
+      }
+    else
+      {
+        int flag =
+          IDADense (mem, num);
+        if (flag != 0)
+          {
+            error ("IDADense solver not initialized");
+          }
+        if (havejac)
+          {
+            flag = IDADlsSetDenseJacFn (mem, IDA::jacdense);
+            if (flag != 0)
+              {
+                error ("Dense Jacobian not set");
+              }
+          }
+      }
+  }
+
+  void
+  IDA::jacdense_impl (long int Neq, realtype t, realtype cj,
+                      N_Vector& yy, N_Vector& yyp, DlsMat& JJ)
+  
+  { 
+    BEGIN_INTERRUPT_WITH_EXCEPTIONS;
+
+    ColumnVector y =
+      NVecToCol (yy, Neq);
+
+    ColumnVector yp =
+      NVecToCol (yyp, Neq);
+
+    Matrix jac;
+
+    if (havejacfun)
+      jac = (*jacfun) (y, yp, t, cj, ida_jac);
+    else
+      jac = (*jacdcell) (dfdy, dfdyp, cj);
+
+    std::copy (jac.fortran_vec (),
+               jac.fortran_vec () + jac.numel (),
+               JJ -> data);
+
+    END_INTERRUPT_WITH_EXCEPTIONS;
+  }
+
+  void
+  IDA::jacsparse_impl (realtype t, realtype cj, N_Vector& yy, N_Vector& yyp,
+                       SlsMat& Jac)
+  
+  { 
+    BEGIN_INTERRUPT_WITH_EXCEPTIONS;
+
+    ColumnVector y =
+      NVecToCol (yy, num);
+
+    ColumnVector yp =
+      NVecToCol (yyp, num);
+
+    SparseMatrix jac;
+
+    if (havejacfun)
+      jac = (*jacspfun) (y, yp, t, cj, ida_jac);
+    else
+      jac = (*jacspcell) (spdfdy, spdfdyp, cj);
+
+    SlsSetToZero (Jac);
+
+    for (int i = 0; i < num + 1; i++)
+      Jac -> colptrs [i] = jac.cidx (i);
+
+    for (int i = 0; i < jac.nnz (); i++)
+      {
+        Jac -> rowvals [i] = jac.ridx (i);
+        Jac -> data [i] = jac.data (i);
+      }    
+
+    END_INTERRUPT_WITH_EXCEPTIONS;
+  }
+
+  ColumnVector
+  IDA::NVecToCol (N_Vector& v, long int n)
+  {
+    ColumnVector data (n);
+    realtype *punt;
+    punt = NV_DATA_S (v);  
+
+    for (octave_idx_type i = 0; i < n; i++)
+      data (i) = punt [i];
+  
+    return data;
+  }
+
+  N_Vector
+  IDA::ColToNVec (const ColumnVector &data, long int n)
+  {
+    N_Vector v =
+      N_VNew_Serial (n);
+
+    realtype * punt;
+    punt = NV_DATA_S (v);
+
+    for (octave_idx_type i = 0; i < n; i++)
+      punt [i] = data (i);
+  
+    return v;
+  }
+
+  void
+  IDA::set_userdata (void)
+  {
+    void * userdata = this;
+
+    int flag =
+      IDASetUserData(mem, userdata);
+    if (flag != 0)
+      {
+        error ("User data not set");
+      }
+  }
+
+  void
+  IDA::initialize (void)
+  {  
+    num = y0.numel();   
+    mem = IDACreate ();
+  
+    N_Vector yy =
+      ColToNVec(y0, num);
+
+    N_Vector yyp =
+      ColToNVec(yp0, num);
+
+    IDA::set_userdata ();
+
+    int flag =
+      IDAInit (mem, IDA::resfun, t0, yy, yyp);
+    if (flag != 0)
+      {
+        error ("IDA not initialized");
+      }
+  }
+
+  void
+  IDA::set_tolerance (ColumnVector& abstol, realtype reltol)
+  {
+    N_Vector abs_tol =
+      ColToNVec (abstol, num);
+
+    int flag =
+      IDASVtolerances (mem, reltol, abs_tol);
+    if (flag != 0)
+      {
+        error ("IDA: Tolerance not set");
+      }
+    N_VDestroy_Serial (abs_tol);
+  }
+
+  void
+  IDA::set_tolerance (realtype abstol, realtype reltol)
+  { 
+    int flag =
+      IDASStolerances (mem, reltol, abstol);
+    if (flag != 0)
+      {
+        error ("IDA: Tolerance not set");
+      }
+  }
+
+  octave_value_list
+  IDA::integrate (const int numt, const ColumnVector& tspan,
+                  const ColumnVector& y, const ColumnVector& yp,
+                  const int refine, bool haverefine, bool haveoutputfcn, 
+                  octave_function *output_fcn, bool haveoutputsel,
+                  ColumnVector& outputsel, bool haveeventfunction,
+                  octave_function *event_fcn)
+  {  
+    // Set up output
+    ColumnVector tout, yout (num), ypout (num), ysel (outputsel.numel ());
+    ColumnVector ie, te, oldval, oldisterminal, olddir;
+    Matrix output, ye;
+    int cont = 0, flag = 0, temp = 0;
+    bool status = 0;
+    std::string string = "";
+    ColumnVector yold = y;
+    octave_value_list retval;  
+  
+    realtype tsol =
+      tspan (0);
+    realtype tend =
+      tspan (numt - 1);
+    
+    N_Vector yyp =
+      ColToNVec (yp, num);
+    
+    N_Vector yy =
+      ColToNVec (y, num);  
+  
+    // Initialize OutputFcn
+    if (haveoutputfcn)
+      status = IDA::outputfun (output_fcn, haveoutputsel, y,
+                               tsol, tend, outputsel, "init");
+
+    // Initialize Events
+    if (haveeventfunction)
+      status = IDA::event (event_fcn, te, ye, ie, tsol, y,
+                           "init", yp, oldval, oldisterminal,
+                           olddir, cont, temp, tsol, yold);
+
+    if (numt > 2)
+      {
+        // First output value
+        tout.resize (numt);
+        tout (0) = tsol;
+        output.resize (numt, num);
+
+        for (octave_idx_type i = 0; i < num; i++)
+          output.elem (0, i) = y.elem (i);
+
+        //Main loop 
+        for (octave_idx_type j = 1; j < numt && status == 0; j++)
+          {
+            // IDANORMAL already interpolates tspan(j)
+            flag = IDASolve (mem, tspan (j), &tsol, yy, yyp, IDA_NORMAL);
+            if (flag != 0)
+              {
+                error ("IDASolve failed");
+              }
+      
+            yout = NVecToCol (yy, num);
+            ypout = NVecToCol (yyp, num);
+            tout (j) = tsol;      
+
+            for (octave_idx_type i = 0; i < num; i++)
+              output.elem (j, i) = yout.elem (i);
+      
+            if (haveoutputfcn)
+              status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
+                                       tend, outputsel, string);
+
+            if (haveeventfunction)
+              status = IDA::event (event_fcn, te, ye, ie, tout (j), yout,
+                                   string, ypout, oldval, oldisterminal,
+                                   olddir, j, temp, tout (j - 1), yold);
+
+            // If integration is stopped, return only the reached steps
+            if (status == 1)
+              {
+                output.resize (j + 1, num);
+                tout.resize (j + 1);
+              }
+
+          }
+      }
+    else // numel (tspan) == 2
+      { 
+        // First output value
+        tout.resize (1);
+        tout (0) = tsol;
+        output.resize (1, num);
+
+        for (octave_idx_type i = 0; i < num; i++)
+          output.elem (0, i) = y.elem (i);
+
+        bool posdirection =
+          (tend > tsol);
+
+        //main loop
+        while (((posdirection == 1 && tsol < tend)
+               || (posdirection == 0 && tsol > tend))
+               && status == 0)
+          {
+            flag = IDASolve (mem, tend, &tsol, yy, yyp, IDA_ONE_STEP);
+            if (flag != 0)
+              {
+                error ("IDASolve failed");
+              }
+
+            if (haverefine)
+              status = IDA::interpolate (cont, output, tout, refine, tend,
+                                         haveoutputfcn, haveoutputsel,
+                                         output_fcn, outputsel,
+                                         haveeventfunction, event_fcn, te,
+                                         ye, ie, oldval, oldisterminal,
+                                         olddir, temp, yold);
+      
+            ypout = NVecToCol (yyp, num);
+            cont += 1;
+            output.resize (cont + 1, num); // This may be not efficient
+            tout.resize (cont + 1);
+            tout (cont) = tsol;      
+            yout = NVecToCol (yy, num);
+
+            for (octave_idx_type i = 0; i < num; i++)
+              output.elem (cont, i) = yout.elem (i);
+
+            if (haveoutputfcn && ! haverefine && tout (cont) < tend)
+              status = IDA::outputfun (output_fcn, haveoutputsel, yout, tsol,
+                                       tend, outputsel, string);
+     
+            if (haveeventfunction && ! haverefine && tout (cont) < tend)
+              status = IDA::event (event_fcn, te, ye, ie, tout (cont), yout,
+                                   string, ypout, oldval, oldisterminal,
+                                   olddir, cont, temp, tout (cont - 1), yold);
+          }
+        if (status == 0)
+          {
+            // Interpolate in tend
+            N_Vector dky = 
+              N_VNew_Serial (num);
+            
+            flag = IDAGetDky (mem, tend, 0, dky);
+            if (flag != 0)
+              {
+                error ("IDA failed to interpolate y");
+              }
+
+            tout (cont) = tend;
+            yout = NVecToCol (dky, num);
+
+            for (octave_idx_type i = 0; i < num; i++)
+              output.elem (cont, i) = yout.elem (i);
+
+            // Plot final value 
+            if (haveoutputfcn)
+              {
+                status = IDA::outputfun (output_fcn, haveoutputsel, yout,
+                                         tend, tend, outputsel, string);
+
+                // Events during last step
+                if (haveeventfunction)
+                  status = IDA::event (event_fcn, te, ye, ie, tend, yout,
+                                       string, ypout, oldval, oldisterminal,
+                                       olddir, cont, temp, tout (cont - 1),
+                                       yold);
+              }
+ 
+            N_VDestroy_Serial (dky);
+          }
+        // Cleanup plotter
+        status = IDA::outputfun (output_fcn, haveoutputsel, yout, tend, tend,
+                                 outputsel, "done");
+
+      }
+
+    retval (0) = tout;
+    retval (1) = output;
+    retval (2) = te;
+    retval (3) = ye;
+    retval (4) = ie;
+
+    return retval;
+  }
+
+  bool
+  IDA::event (octave_function *event_fcn,
+              ColumnVector& te, Matrix& ye, ColumnVector& ie,
+              realtype tsol, const ColumnVector& y, std::string flag,
+              const ColumnVector& yp, ColumnVector& oldval,
+              ColumnVector& oldisterminal, ColumnVector& olddir, int cont,
+              int& temp, realtype told, ColumnVector& yold)
+  {
+    bool status = 0;
+    octave_value_list args (3);
+    octave_value_list output (3);
+    ColumnVector val, isterminal, dir;
+    args (0) = tsol;
+    args (1) = y;
+    args (2) = yp;
+
+    // cont is the number of steps reached by the solver
+    // temp is the number of events registered
+
+    if (flag == "init")
+      {
+        output = feval (event_fcn, args, 3);
+        oldval = output(0).vector_value ();
+        oldisterminal = output(1).vector_value ();
+        olddir = output(2).vector_value ();
+      }
+    else if (flag == "")
+      {
+        ColumnVector index (0);
+        output = feval (event_fcn, args, 3);
+        val = output(0).vector_value ();
+        isterminal = output(1).vector_value ();
+        dir = output(2).vector_value ();
+
+        // Get the index of the changed values
+        for (octave_idx_type i = 0; i < val.numel (); i++)
+          {
+            if ((val(i) > 0 && oldval(i) < 0 && dir(i) != -1) // increasing
+                || (val(i) < 0 && oldval(i) > 0 && dir(i) != 1)) // decreasing
+              {
+                index.resize (index.numel () + 1);
+                index (index.numel () - 1) = i;
+              }
+          }
+    
+        if (cont == 1 && index.numel () > 0)  // Events in first step
+          {
+            temp = 1; // register only the first event
+            te.resize (1);
+            ye.resize (1, num);
+            ie.resize (1);
+      
+            // Linear interpolation
+            ie (0) = index (0);
+            te (0) = tsol - val (index (0)) * (tsol - told)
+              / (val (index (0)) - oldval (index (0)));
+
+            ColumnVector ytemp =
+              y - ((tsol - te (0)) * (y - yold ) / (tsol - told));
+      
+            for (octave_idx_type i = 0; i < num; i++)
+              ye.elem (0, i) = ytemp.elem (i);      
+             
+          }
+        else if (index.numel () > 0) 
+          // Not first step: register all events and test if stop integration or not
+          {
+            te.resize (temp + index.numel ());
+            ye.resize (temp + index.numel (), num);
+            ie.resize (temp + index.numel ());
+      
+            for (octave_idx_type i = 0; i < index.numel (); i++)
+              {
+
+                if (isterminal (index (i)) == 1)
+                  status = 1; // Stop integration
+        
+                // Linear interpolation  
+                ie (temp + i) = index (i);
+                te (temp + i) = tsol -
+                  val (index (i)) * (tsol - told) / 
+                  (val (index (i)) - oldval (index (i)));
+
+                ColumnVector ytemp =
+                  y - (tsol - te (temp + i)) * (y - yold) / (tsol - told);
+       
+                for (octave_idx_type j = 0; j < num; j++)
+                  ye.elem (temp + i, j) = ytemp.elem (j);  
+  
+              }
+
+            temp += index.numel ();
+          }
+        
+        // Update variables
+        yold = y;
+        told = tsol;
+        olddir = dir;
+        oldval = val;
+        oldisterminal = isterminal;
+      }
+
+    return status;
+  }
+
+  bool
+  IDA::interpolate (int& cont, Matrix& output, ColumnVector& tout,
+                    int refine, realtype tend, bool haveoutputfcn,
+                    bool haveoutputsel, octave_function *output_fcn,
+                    ColumnVector& outputsel, bool haveeventfunction,
+                    octave_function * event_fcn, ColumnVector& te,
+                    Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
+                    ColumnVector& oldisterminal, ColumnVector& olddir,
+                    int& temp, ColumnVector& yold)
+  {
+    realtype h = 0, tcur = 0;
+    bool status = 0;
+   
+    N_Vector dky =
+      N_VNew_Serial (num);
+    
+    N_Vector dkyp =
+      N_VNew_Serial (num);
+    
+    ColumnVector yout (num);
+    ColumnVector ypout (num);
+    std::string string = "";
+
+    int flag =
+      IDAGetLastStep (mem, &h);
+    
+    if (flag != 0)
+      {
+        error ("IDA failed to return last step");
+      }
+    flag = IDAGetCurrentTime (mem, &tcur);
+    if (flag != 0)
+      {
+        error ("IDA failed to return the current time");
+      }
+   
+    realtype tin = 
+      tcur - h;
+
+    realtype step =
+      h / refine;
+
+    for (octave_idx_type i = 1; i < refine && tin + step * i < tend 
+           && status == 0; i++)
+      {
+        flag = IDAGetDky (mem, tin + step*i, 0, dky);
+        if (flag != 0)
+          {
+            error ("IDA failed to interpolate y");
+          }
+        flag = IDAGetDky (mem, tin + step*i, 1, dkyp);
+        if (flag != 0)
+          {
+            error ("IDA failed to interpolate yp");
+          }
+        cont += 1;
+        output.resize (cont + 1, num); 
+        tout.resize (cont + 1);
+
+        tout (cont) = tin + step * i;      
+        yout = NVecToCol (dky, num);
+        ypout = NVecToCol (dkyp, num);
+
+        for (octave_idx_type j = 0; j < num; j++)
+          output.elem (cont, j) = yout.elem (j);
+    
+        if (haveoutputfcn)
+          status = IDA::outputfun (output_fcn, haveoutputsel, yout,
+                                   tout (cont), tend, outputsel, "");
+
+        if (haveeventfunction)
+          status = IDA::event (event_fcn, te, ye, ie, tout (cont),
+                               yout, string, ypout, oldval,
+                               oldisterminal, olddir, cont, temp,
+                               tout (cont - 1), yold);
+      }
+    N_VDestroy_Serial (dky);
+    return status;
+  }
+
+  bool
+  IDA::outputfun (octave_function *output_fcn, bool haveoutputsel, 
+                  const ColumnVector& yout, realtype tsol,
+                  realtype tend, ColumnVector& outputsel,
+                  std::string flag)
+  {
+    bool status = 0;
+    octave_value_list output, val;
+    ColumnVector ysel (outputsel.numel ());
+
+    if (haveoutputsel)
+      {
+        for (octave_idx_type i = 0; i < outputsel.numel (); i++)
+          ysel (i) = yout (outputsel (i));
+      
+        output (1) = ysel;
+      }
+    else
+      output (1) = yout;    
+
+    output (2) = flag;
+
+    if (flag == "init")
+      {  
+        ColumnVector toutput (2);
+        toutput (0) = tsol;
+        toutput (1) = tend;
+        output (0) = toutput;
+  
+        feval (output_fcn, output, 0);
+      } 
+    else if (flag == "")
+      {
+        output (0) = tsol;
+        val = feval (output_fcn, output, 1);
+        status = val(0).bool_value ();
+      }
+    else
+      {  // Cleanup plotter
+        output (0) = tend;
+        feval (output_fcn, output, 0);
+      }
+
+    return status;
+  }
+
+  void
+  IDA::set_maxstep (realtype maxstep)
+  {
+    int flag = 
+      IDASetMaxStep (mem, maxstep);
+
+    if (flag != 0)
+      {
+        error ("IDA: Max Step not set");
+      }
+  } 
+
+  void
+  IDA::set_initialstep (realtype initialstep) 
+  {
+    int flag =
+      IDASetInitStep (mem, initialstep);
+
+    if (flag != 0)
+      {
+        error ("IDA: Initial Step not set"); 
+      }
+  } 
+
+  void
+  IDA::set_maxorder (int maxorder)  
+  {
+    int flag =
+      IDASetMaxOrd (mem, maxorder);
+
+    if (flag != 0)
+      {
+        error ("IDA: Max Order not set");
+      }
+  } 
+
+  void
+  IDA::print_stat (void)
+  {
+    long int nsteps = 0, netfails = 0, nrevals = 0;
+    int flag =
+      IDAGetNumSteps(mem, &nsteps);
+
+    if (flag != 0)
+      {
+        error ("IDA failed to return the number of internal steps");
+      }
+    flag = IDAGetNumErrTestFails(mem, &netfails);
+    if (flag != 0)
+      {
+        error ("IDA failed to return the number of internal errors");
+      }
+    flag = IDAGetNumResEvals(mem, &nrevals);
+    if (flag != 0)
+      {
+        error ("IDA failed to return the number of residual evaluations");
+      }  
+
+    std::cout<<nsteps<<" successful steps\n";
+    std::cout<<netfails<<" failed attempts\n";
+    std::cout<<nrevals<<" function evaluations\n";
+    //std::cout<<<<" partial derivatives\n";
+    //std::cout<<<<" LU decompositions\n";
+    //std::cout<<<<" solutions of linear systems\n";
+  }
+ 
+  ColumnVector
+  ida_user_function (const ColumnVector& x, const ColumnVector& xdot,
+                     double t, octave_function *ida_fc)
+  {
+    ColumnVector retval;
+    octave_value_list args;
+
+    args(2) = xdot;
+    args(1) = x;
+    args(0) = t;
+
+    octave_value_list tmp;
+    
+    try
+      {
+        tmp = ida_fc -> do_multi_index_op (1, args);
+      }
+    catch (octave::execution_exception& e)
+      {
+        err_user_supplied_eval (e, "__ode15__");
+      }
+
+    retval = tmp(0).vector_value ();
+
+    return retval;
+  }
+
+  Matrix
+  ida_dense_jac (const ColumnVector& x, const ColumnVector& xdot,
+                 double t, double cj, octave_function *ida_jc)
+  {
+    Matrix retval;
+    octave_value_list newargs (3);
+
+    newargs (0) = t;
+    newargs (1) = x;
+    newargs (2) = xdot;
+
+    octave_value_list tmp;
+    
+    try
+      {
+        tmp = ida_jc -> do_multi_index_op (2, newargs);
+      }
+    catch (octave::execution_exception& e)
+      {
+        err_user_supplied_eval (e, "__ode15__");
+      }
+
+    retval = tmp(0).matrix_value () + cj * tmp(1).matrix_value ();
+
+    return retval;
+  }
+
+  SparseMatrix
+  ida_sparse_jac (const ColumnVector& x, const ColumnVector& xdot,
+                  double t, double cj, octave_function *ida_jc)
+  {
+    SparseMatrix retval;
+    octave_value_list newargs (3);
+
+    newargs (0) = t;
+    newargs (1) = x;
+    newargs (2) = xdot;
+  
+    octave_value_list tmp;
+
+    try
+      {
+        tmp = ida_jc -> do_multi_index_op (2, newargs);
+      }
+    catch (octave::execution_exception& e)
+      {
+        err_user_supplied_eval (e, "__ode15__");
+      }
+
+    retval = tmp(0).sparse_matrix_value () +
+      cj * tmp(1).sparse_matrix_value ();
+    
+    return retval;
+  }
+
+  Matrix
+  ida_dense_cell_jac (Matrix *dfdy, Matrix *dfdyp, double cj)
+  {
+    Matrix retval;
+    retval = (*dfdy) + cj * (*dfdyp);
+    return retval;
+  }
+
+  SparseMatrix
+  ida_sparse_cell_jac (SparseMatrix *spdfdy, SparseMatrix *spdfdyp,
+                       double cj)
+  {
+    SparseMatrix retval;
+    retval = (*spdfdy) + cj * (*spdfdyp);
+    return retval;
+  }
+
+  octave_value_list
+  do_ode15 (octave_function *ida_fcn,
+            const ColumnVector &tspan,
+            const int numt,
+            const realtype t0,
+            const ColumnVector &y0,
+            const ColumnVector &yp0,
+            const octave_scalar_map &options)
+  {
+    octave_value_list retval;
+  
+    // Create object
+    IDA dae (t0, y0, yp0, ida_fcn, ida_user_function);
+
+    // Set Jacobian
+    bool havejac =
+      options.getfield ("havejac").bool_value ();
+    
+    bool havejacsparse =
+      options.getfield ("havejacsparse").bool_value ();
+    
+    bool havejacfun =
+      options.getfield ("havejacfun").bool_value ();
+ 
+    Matrix ida_dfdy, ida_dfdyp, *dfdy, *dfdyp;
+    SparseMatrix ida_spdfdy, ida_spdfdyp, *spdfdy, *spdfdyp;
+    octave_function *ida_jac;
+    Cell jaccell;
+
+    if (havejac)
+      {
+        if (havejacfun)
+          {
+            ida_jac = options.getfield ("Jacobian").function_value ();
+            if (havejacsparse) 
+              dae.set_jacobian (ida_jac, ida_sparse_jac);
+            else
+              dae.set_jacobian (ida_jac, ida_dense_jac);
+          }
+        else
+          {
+            jaccell = options.getfield ("Jacobian").cell_value ();
+
+            if (havejacsparse) 
+              {
+                ida_spdfdy = jaccell(0).sparse_matrix_value ();
+                ida_spdfdyp = jaccell(1).sparse_matrix_value ();
+                spdfdy = &ida_spdfdy;
+                spdfdyp = &ida_spdfdyp;
+                dae.set_jacobian (spdfdy, spdfdyp, ida_sparse_cell_jac);
+              }
+            else
+              {
+                ida_dfdy = jaccell(0).matrix_value ();
+                ida_dfdyp = jaccell(1).matrix_value ();
+                dfdy = &ida_dfdy;
+                dfdyp = &ida_dfdyp;
+                dae.set_jacobian (dfdy, dfdyp, ida_dense_cell_jac);
+              }
+          }
+      }
+  
+    // Initialize IDA
+    dae.initialize ();
+ 
+    // Set tolerances  
+    realtype rel_tol =
+      options.getfield("RelTol").double_value ();
+    
+    bool haveabstolvec =
+      options.getfield ("haveabstolvec").bool_value ();
+  
+    if (haveabstolvec)  
+      {
+        ColumnVector abs_tol =
+          options.getfield("AbsTol").vector_value ();
+        
+        dae.set_tolerance (abs_tol, rel_tol);
+      }
+    else
+      {
+        realtype abs_tol =
+          options.getfield("AbsTol").double_value ();
+        
+        dae.set_tolerance (abs_tol, rel_tol);
+      }
+ 
+    //Set max step
+    realtype maxstep =
+      options.getfield("MaxStep").double_value ();
+    
+    dae.set_maxstep (maxstep);
+
+    //Set initial step
+    if (!(options.getfield("InitialStep").is_empty ())) 
+      {
+        realtype initialstep =
+          options.getfield("InitialStep").double_value ();
+        
+        dae.set_initialstep (initialstep);
+      }
+
+    //Set max order FIXME: it doesn't work
+    int maxorder =
+      options.getfield("MaxOrder").int_value ();
+    
+    dae.set_maxorder (maxorder);  
+
+    //Set Refine
+    const int refine =
+      options.getfield("Refine").int_value ();
+    
+    bool haverefine =
+      (refine > 1);
+
+    octave_function *output_fcn = NULL;
+    ColumnVector outputsel;
+
+    // OutputFcn
+    bool haveoutputfunction =
+      options.getfield("haveoutputfunction").bool_value ();
+    
+    if (haveoutputfunction)
+      output_fcn = options.getfield("OutputFcn").function_value ();     
+
+    // OutputSel
+    bool haveoutputsel =
+      options.getfield("haveoutputselection").bool_value ();
+    
+    if (haveoutputsel)
+      outputsel = options.getfield("OutputSel").vector_value (); 
+
+    octave_function *event_fcn = NULL;
+
+    // Events
+    bool haveeventfunction =
+      options.getfield("haveeventfunction").bool_value ();
+
+    if (haveeventfunction)
+      event_fcn = options.getfield("Events").function_value ();     
+
+    // Set up linear solver
+    dae.set_up ();
+
+    // Integrate
+    retval = dae.integrate (numt, tspan, y0, yp0, refine,
+                            haverefine, haveoutputfunction,
+                            output_fcn, haveoutputsel, outputsel,
+                            haveeventfunction, event_fcn);
+ 
+    // Statistics 
+    bool havestats = 
+      options.getfield("havestats").bool_value ();
+
+    if (havestats)
+      dae.print_stat ();
+
+    return retval;
+  }  
+}
+#endif
+
+
+DEFUN_DLD (__ode15__, args, nargout, doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{t}, @var{y} =} __ode15__ (@var{fun}, @
+@var{tspan}, @var{y0}, @var{yp0}, @var{options})
+Undocumented internal function.
+@end deftypefn */)
+{
+
+#if defined (HAVE_SUNDIALS)
+
+  // Check number of parameters
+  int nargin = args.length ();
+
+  if (nargin != 5 || nargout != 5)
+    print_usage ();
+
+  // Check odefun
+  octave_function *ida_fcn = NULL; 
+  
+  octave_value f_arg = args(0);
+
+  if (f_arg.is_function_handle ())
+    ida_fcn = f_arg.function_value ();
+  else
+    error ("__ode15__: odefun must be a function handle");
+
+  // Check input tspan
+  ColumnVector tspan =
+    args(1).xvector_value ("__ode15__: TRANGE must be a vector of numbers");
+  
+  int numt =
+    tspan.numel ();
+  
+  realtype t0 =
+    tspan (0);
+
+  if (numt < 2) 
+    error ("__ode15__: TRANGE must contain at least 2 elements");
+  else if (!(tspan.is_sorted ()) || (tspan(0) == tspan(numt - 1)))
+    error ("__ode15__: TRANGE must be strictly monotonic");
+
+  // input y0 and yp0
+  ColumnVector y0  =
+    args(2).xvector_value ("__ode15__: initial state y0 must be a vector");
+  
+  ColumnVector yp0 =
+    args(3).xvector_value ("__ode15__: initial state yp0 must be a vector"); 
+
+
+  if (y0.numel () != yp0.numel ())
+    error ("__ode15__: initial state y0 and yp0 must have the same length");
+  else if (y0.numel () < 1)
+    error ("__ode15__: initial state yp0 must be a vector or a scalar");
+
+
+  if (! args(4).is_map ())
+    error ("__ode15__: OPTS argument must be a structure");
+    
+  octave_scalar_map options = 
+    args(4).xscalar_map_value ("__ode15__:",
+    "OPTS argument must be a scalar structure");
+ 
+
+  return octave::do_ode15 (ida_fcn, tspan, numt, t0,
+                           y0, yp0, options);
+  
+
+#else
+
+  octave_unused_parameter (args);
+  err_disabled_feature ("__ode15__", "sundials_ida, sundials_nvecserial");
+
+#endif
+}
+
+
+
--- a/libinterp/dldfcn/module-files	Tue Aug 23 02:31:51 2016 +0200
+++ b/libinterp/dldfcn/module-files	Tue Aug 23 03:19:11 2016 +0200
@@ -5,6 +5,7 @@
 __glpk__.cc|$(GLPK_CPPFLAGS)|$(GLPK_LDFLAGS)|$(GLPK_LIBS)
 __init_fltk__.cc|$(FLTK_CPPFLAGS) $(FT2_CPPFLAGS) $(FONTCONFIG_CPPFLAGS)|$(FLTK_LDFLAGS) $(FT2_LDFLAGS)|$(FLTK_LIBS) $(FT2_LIBS) $(OPENGL_LIBS)
 __init_gnuplot__.cc|$(FT2_CPPFLAGS) $(FONTCONFIG_CPPFLAGS)||
+__ode15__.cc|$(SUNDIALS_XCPPFLAGS)|$(SUNDIALS_XLDFLAGS)|$(SUNDIALS_XLIBS)
 __osmesa_print__.cc|$(OSMESA_CPPFLAGS) $(FT2_CPPFLAGS)|$(OSMESA_LDFLAGS)|$(OSMESA_LIBS)
 __voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS)
 amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS)
--- a/scripts/ode/decic.m	Tue Aug 23 02:31:51 2016 +0200
+++ b/scripts/ode/decic.m	Tue Aug 23 03:19:11 2016 +0200
@@ -91,7 +91,7 @@
   if (nargin < 6 || nargin > 7 || nargout > 3)
     print_usage ();
   endif
-
+ 
   #Check input
   if (! isa (odefun, "function_handle"))
     error ("Octave:invalid-input-arg",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ode/ode15i.m	Tue Aug 23 03:19:11 2016 +0200
@@ -0,0 +1,543 @@
+## Copyright (C) 2016, Francesco Faccio <francesco.faccio@mail.polimi.it>
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {[@var{t}, @var{y}] =} ode15i (@var{fun}, @var{trange}, @var{y0}, @var{yp0})
+## @deftypefnx {} {[@var{t}, @var{y}] =} ode15i (@var{fun}, @var{trange}, @var{y0}, @var{yp0}, @var{ode_opt})
+## @deftypefnx {} {[@var{t}, @var{y}, @var{te}, @var{ye}, @var{ie}] =} ode15i (@dots{})
+## @deftypefnx {} {@var{solution} =} ode15i (@dots{})
+##
+## Solve a set of full-implicit Ordinary Differential Equations and 
+## Differential Algebraic Equations (DAEs) of index 1, with the variable-step,
+## variable order BDF (Backward Differentiation Formula) method, which
+## ranges from order 1 to 5.
+##
+## @var{fun} is a function handle, inline function, or string containing the
+## name of the function that defines the ODE: @code{f(@var{t},@var{y},@var{yp})}.
+## The function must accept three inputs where the first is time @var{t}, the
+## second is a column vector of unknowns @var{y} and the third is a column
+## vector of unknowns @var{yp}. 
+##
+## @var{trange} specifies the time interval over which the ODE will be
+## evaluated.  Typically, it is a two-element vector specifying the initial and
+## final times (@code{[tinit, tfinal]}).  If there are more than two elements
+## then the solution will also be evaluated at these intermediate time.
+##
+## @var{y0} and @var{yp0} contain the initial values for the unknowns @var{y}
+## and @var{yp}.  If they are row vectors then the solution @var{y} will be a
+## matrix in which each column is the solution for the corresponding initial
+## value in @var{y0} and @var{yp0}.
+##
+## @var{y0} and @var{yp0} must be consistent initial conditions, meaning that
+## @code{f(@var{t},@var{y0},@var{yp0})=0} is satisfied. You can use function
+## decic to compute consistent initial conditions, given initial guesses.
+##
+## The optional fifth argument @var{ode_opt} specifies non-default options to
+## the ODE solver.  It is a structure generated by @code{odeset}.
+##
+## The function typically returns two outputs.  Variable @var{t} is a
+## column vector and contains the times where the solution was found.  The
+## output @var{y} is a matrix in which each column refers to a different
+## unknown of the problem and each row corresponds to a time in @var{t}.
+##
+## The output can also be returned as a structure @var{solution} which
+## has field @var{x} containing the time where the solution was evaluated and
+## field @var{y} containing the solution matrix for the times in @var{x}.
+## Use @code{fieldnames (@var{solution})} to see the other fields and
+## additional information returned.
+##
+## If using the @qcode{"Events"} option then three additional outputs may
+## be returned.  @var{te} holds the time when an Event function returned a
+## zero.  @var{ye} holds the value of the solution at time @var{te}.  @var{ie}
+## contains an index indicating which Event function was triggered in the case
+## of multiple Event functions.
+##
+## This function can be called with two output arguments: @var{t} and @var{y}.
+## Variable @var{t} is a column vector and contains the time stamps, instead
+## @var{y} is a matrix in which each column refers to a different unknown of
+## the problem and the rows number is the same of @var{t} rows number so
+## that each row of @var{y} contains the values of all unknowns at the time
+## value contained in the corresponding row in @var{t}.
+##
+## Example: Solve the @nospell{Robetson}'s equations:
+##
+## @example
+## @group
+## function res = robertsidae(@var{t}, @var{y}, @var{yp})
+## res = [-(@var{yp}(1) + 0.04*@var{y}(1) - 1e4*@var{y}(2)*@var{y}(3));
+##        -(@var{yp}(2) - 0.04*@var{y}(1) + 1e4*@var{y}(2)*@var{y}(3) +
+##        3e7*@var{y}(2)^2);
+##        @var{y}(1) + @var{y}(2) + @var{y}(3) - 1];
+## endfunction
+## [@var{t},@var{y}] = ode15i (@@robertsidae, [0 1e3], [1; 0; 0],[-1e-4; 1e-4; 0]);
+## @end group
+## @end example
+## @seealso{decic, odeset, odeget}
+## @end deftypefn
+
+function varargout = ode15i (fun, trange, y0, yp0, varargin)
+
+  solver = 'ode15i';  
+ 
+  if (nargin < 4)
+    print_usage ();
+  endif
+  
+  n = numel (y0);
+  
+  if (nargin > 4)
+   options = varargin{1};
+  else
+   options = odeset ();
+  endif
+
+  ## Check fun, trange, y0, yp0
+  fun = check_default_input (fun, trange, solver, y0, yp0);
+  
+  if (! isempty (options.Jacobian))
+    if (ischar (options.Jacobian))
+      try
+        options.Jacobian = str2func (options.Jacobian);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.Jacobian, "function_handle"))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+      endif
+    endif
+  endif
+
+  if (! isempty (options.OutputFcn))
+    if (ischar (options.OutputFcn))
+      try
+        options.OutputFcn = str2func (options.OutputFcn);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.OutputFcn, "function_handle"))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "OutputFcn");
+      endif
+    endif
+  endif
+
+  if (! isempty (options.Events))
+    if (ischar (options.Events))
+      try
+        options.Events = str2func (options.Events);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.Events, "function_handle") && ! ismatrix (options.Events))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Events");
+      endif
+    endif
+  endif
+
+  persistent defaults   = [];
+  persistent classes    = [];
+  persistent attributes = [];
+
+  [defaults, classes, attributes] = odedefaults (n, trange(1),
+                                                 trange(end));
+
+  defaults   = rmfield (defaults,   {"NonNegative", "Mass", ...
+                                     "MStateDependence", "MvPattern", ...
+                                     "MassSingular", "InitialSlope", "BDF"});
+  classes    = rmfield (classes,    {"NonNegative", "Mass", ...
+                                     "MStateDependence", "MvPattern", ...
+                                     "MassSingular", "InitialSlope", "BDF"});
+  attributes = rmfield (attributes, {"NonNegative", "Mass", ...
+                                     "MStateDependence", "MvPattern", ...
+                                     "MassSingular", "InitialSlope", "BDF"});
+
+  classes        = odeset (classes, 'Vectorized', {});
+  attributes     = odeset (attributes, 'Jacobian', {}, 'Vectorized', {});
+
+  options = odemergeopts (options, defaults, classes, attributes, solver);
+
+  ## Jacobian
+  options.havejac       = false;
+  options.havejacsparse = false;
+  options.havejacfun    = false;
+
+  if (! isempty (options.Jacobian))
+    options.havejac = true;
+    if (iscell (options.Jacobian)) 
+      if (numel (options.Jacobian) == 2)
+        if (issparse (options.Jacobian{1}) && issparse (options.Jacobian{2})) ## Jac is sparse cell
+          options.havejacsparse = true;
+        endif
+
+        if (any (size (options.Jacobian{1}) != [n n])
+            || any (size (options.Jacobian{2}) != [n n])
+            || ! isnumeric (options.Jacobian{1})
+            || ! isnumeric (options.Jacobian{2})
+            || ! isreal (options.Jacobian{1})
+            || ! isreal (options.Jacobian{2}))
+          error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+        endif
+      else
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+      endif
+
+    elseif (isa (options.Jacobian, "function_handle"))  
+      options.havejacfun = true;
+      if (nargin (options.Jacobian) == 3)
+        [A, B] = options.Jacobian (trange(1), y0, yp0);
+        if (issparse (A) && issparse (B))
+          options.havejacsparse = true;  ## Jac is sparse fun
+        endif
+
+        if (any (size (A) != [n n]) || any (size (B) != [n n])
+            || ! isnumeric (A) || ! isnumeric (B) || ! isreal (A)
+            || ! isreal (B))
+          error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+        endif
+      else
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+      endif
+    else
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+    endif
+  endif
+  
+  ## Abstol and Reltol
+
+  options.haveabstolvec = false;
+
+  if (numel (options.AbsTol) != 1 && numel (options.AbsTol) != n)
+    error ("Octave:invalid-input-arg",
+           [solver ": invalid value assigned to field '%s'"], "AbsTol");
+  
+  elseif (numel (options.AbsTol) == n)
+    options.haveabstolvec = true;
+  endif
+
+  ## Stats
+  options.havestats = false;    
+  if (strcmp (options.Stats, "on"))
+    options.havestats = true;    
+  endif
+
+  ## Don't use Refine when the output is a structure
+  if (nargout == 1)
+    options.Refine = 1;
+  endif
+
+  ## OutputFcn and OutputSel
+  if (isempty (options.OutputFcn) && nargout == 0)
+    options.OutputFcn = @odeplot;
+    options.haveoutputfunction = true;
+  else
+    options.haveoutputfunction = ! isempty (options.OutputFcn);
+  endif
+  
+  options.haveoutputselection = ! isempty (options.OutputSel);
+  if (options.haveoutputselection)
+    options.OutputSel = options.OutputSel - 1;
+  endif
+
+  ## Events
+  options.haveeventfunction = ! isempty (options.Events);
+
+
+  [t, y, te, ye, ie] = __ode15__ (fun, trange, y0, yp0, options);
+  
+
+  if (nargout == 2)
+    varargout{1} = t;
+    varargout{2} = y;
+  elseif (nargout == 1)
+    varargout{1}.x = t;    # Time stamps are saved in field x
+    varargout{1}.y = y;    # Results are saved in field y
+    varargout{1}.solver = solver; 
+    if (options.haveeventfunction)
+      varargout{1}.xe = te;  # Time info when an event occurred
+      varargout{1}.ye = ye;  # Results when an event occurred
+      varargout{1}.ie = ie;  # Index info which event occurred
+    endif
+  elseif (nargout == 5)
+    varargout = cell (1,5);
+    varargout{1} = t;
+    varargout{2} = y;
+    if (options.haveeventfunction)
+      varargout{3} = te;  # Time info when an event occurred
+      varargout{4} = ye;  # Results when an event occurred
+      varargout{5} = ie;  # Index info which event occurred
+    endif
+  endif
+
+endfunction
+
+%!demo 
+%! 
+%! ##Solve Robertson's equations with ode15i
+%! fun = @ (t, y, yp) [-(yp(1) + 0.04*y(1) - 1e4*y(2)*y(3));
+%!                     -(yp(2) - 0.04*y(1) + 1e4*y(2)*y(3) + 3e7*y(2)^2);
+%!                     y(1) + y(2) + y(3) - 1];
+%!
+%! opt = odeset ('RelTol',1e-4, 'AbsTol', [1e-8, 1e-14, 1e-6]);
+%! y0 = [1; 0; 0];
+%! yp0 = [-1e-4; 1e-4; 0];
+%! tspan = [0 4*logspace(-6, 6)];
+%! 
+%! [t, y] = ode15i (fun, tspan, y0, yp0, opt);
+%!
+%! y (:,2) = 1e4 * y (:, 2);
+%! figure (2);
+%! semilogx (t, y, 'o')
+%! xlabel ('time');
+%! ylabel ('species concentration');
+%! title ('Robertson DAE problem with a Conservation Law');
+%! legend ('y1', 'y2', 'y3');
+
+%!function res = rob (t, y, yp)
+%! res =[-(yp(1) + 0.04*y(1) - 1e4*y(2)*y(3));
+%!       -(yp(2) - 0.04*y(1) + 1e4*y(2)*y(3) + 3e7*y(2)^2);
+%!         y(1) + y(2) + y(3) - 1];
+%!endfunction
+%!
+%!function ref = fref()
+%! ref = [100, 0.617234887614937, 0.000006153591397, 0.382758958793666];
+%!endfunction
+%!
+%!function ref2 = fref2()
+%! ref2 = [4e6 0 0 1];
+%!endfunction
+%!
+%!function [DFDY, DFDYP] = jacfundense(t, y, yp)
+%!  DFDY = [-0.04,           1e4*y(3),  1e4*y(2);
+%!           0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!              1,                  1,         1];
+%!  DFDYP = [-1,  0, 0;
+%!            0, -1, 0;
+%!            0,  0, 0];   
+%!endfunction
+%!
+%!function [DFDY, DFDYP] = jacfunsparse(t, y, yp)
+%!  DFDY = sparse ([-0.04,           1e4*y(3),  1e4*y(2);
+%!                   0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!                      1,                  1,         1]);
+%!  DFDYP = sparse ([-1,  0, 0;
+%!                    0, -1, 0;
+%!                    0,  0, 0]);   
+%!endfunction
+%!function [DFDY, DFDYP] = jacwrong(t, y, yp)
+%!  DFDY = [-0.04,           1e4*y(3);
+%!           0.04, -1e4*y(3)-6e7*y(2)];
+%!  DFDYP = [-1,  0;
+%!            0, -1];
+%!endfunction
+%!function [DFDY, DFDYP, A] = jacwrong2(t, y, yp)
+%!  DFDY = [-0.04,           1e4*y(3),  1e4*y(2);
+%!           0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!              1,                  1,         1];
+%!  DFDYP = [-1,  0, 0;
+%!            0, -1, 0;
+%!            0,  0, 0];
+%!  A = DFDY;   
+%!endfunction
+%!function [val, isterminal, direction] = ff (t, y, yp)
+%!  isterminal = [0 1];
+%!  if (t < 1e1)
+%!    val = [-1, -2];
+%!  else
+%!    val = [1 3];
+%!  endif
+%!  
+%!  direction = [1 0];
+%!endfunction
+
+%!test  # anonymous function instead of real function
+%! ref = [0.049787079136413];
+%! ff = @(t, u, udot)  udot + 3 * u;
+%! [t, y] = ode15i (ff, 0:1, 1, -3);
+%! assert ([t(end), y(end)], [1, ref], 1e-3);
+%!test  # function passed as string
+%! [t, y] = ode15i ('rob',[0 100 200], [1;0;0], [-1e-4;1e-4;0]);
+%! assert ([t(2), y(2,:)], fref, 1e-3);
+%!test  #  solve in intermidiate step
+%! [t, y] = ode15i (@rob,[0 100 200], [1;0;0], [-1e-4;1e-4;0]);
+%! assert ([t(2), y(2,:)], fref, 1e-3);
+%!test  # numel(trange) = 2 final value
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0]);
+%! assert ([t(end), y(end,:)], fref, 1e-5);
+%!test  # With empty options
+%! opt = odeset();
+%! [t, y] = ode15i (@rob,[0 1e6 2e6 3e6 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref2, 1e-3);
+%! opt = odeset();
+%!test  # Without options 
+%! [t, y] = ode15i (@rob,[0 1e6 2e6 3e6 4e6], [1;0;0], [-1e-4;1e-4;0]);
+%! assert ([t(end), y(end,:)], fref2, 1e-3);
+%!test  # InitialStep option
+%! opt = odeset ("InitialStep", 1e-8);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(2)-t(1)], [1e-8], 1e-9);
+%!test  # MaxStep option
+%! opt = odeset ("MaxStep", 1e-3);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0]);
+%! assert ([t(5)-t(4)], [1e-3], 1e-3);
+%!test  # AbsTol scalar option
+%! opt = odeset ("AbsTol", 1e-8);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # AbsTol scalar and RelTol option
+%! opt = odeset ("AbsTol", 1e-8, "RelTol", 1e-6);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # AbsTol vector option
+%! opt = odeset ("AbsTol", [1e-8, 1e-14,1e-6]);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # AbsTol vector and RelTol option
+%! opt = odeset ("AbsTol", [1e-8, 1e-14,1e-6], "RelTol", 1e-6);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # RelTol option
+%! opt = odeset ("RelTol", 1e-6);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # Jacobian fun dense
+%! opt = odeset ("Jacobian", @jacfundense);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # Jacobian fun dense as string
+%! opt = odeset ("Jacobian", 'jacfundense');
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # Jacobian fun sparse
+%! opt = odeset ("Jacobian", @jacfunsparse, "AbsTol", 1e-7, "RelTol", 1e-7);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), y(end,:)], fref, 1e-3);
+%!test  # Solve in backward direction starting at t=100
+%! YPref = [-0.001135972751027; -0.000000027483627; 0.001136000234654];
+%! Yref = [0.617234887614937, 0.000006153591397, 0.382758958793666];
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0]);
+%! [t2, y2] = ode15i (@rob,[100 0], Yref', YPref);
+%! assert ([t2(end), y2(end,:)], [0 1 0 0], 2e-2);
+#%!test  # Solve in backward direction with MaxStep option
+%! YPref = [-0.001135972751027; -0.000000027483627; 0.001136000234654];
+%! Yref = [0.617234887614937, 0.000006153591397, 0.382758958793666];
+%! opt = odeset ('MaxStep', 1e-2);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0]);
+%! [t2, y2] = ode15i (@rob,[100 0], Yref', YPref, opt);
+%! assert ([t2(end), y2(end,:)], [0 1 0 0], 2e-2);
+%! assert ([t2(9)-t2(10)], [1e-2], 1e-2);
+#%!test  # Solve in backward direction starting  with intermidiate step
+%! YPref = [-0.001135972751027; -0.000000027483627; 0.001136000234654];
+%! Yref = [0.617234887614937, 0.000006153591397, 0.382758958793666];
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0]);
+%! [t2, y2] = ode15i (@rob,[100 5 0], Yref', YPref);
+%! assert ([t2(end), y2(end,:)], [0 1 0 0], 2e-2);
+%!test  # Refine
+%! opt = odeset ("Refine", 3);
+%! [t, y] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0]);
+%! [t2, y2] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([numel(t2)], numel(t)*3, 3);
+%!test  # Refine ignored if numel (trange) > 2
+%! opt = odeset ("Refine", 3);
+%! [t, y] = ode15i (@rob,[0 10 100], [1;0;0], [-1e-4;1e-4;0]);
+%! [t2, y2] = ode15i (@rob,[0 10 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([numel(t2)], numel(t));
+%!test  # Events option add further elements in sol
+%! opt = odeset ("Events", @ff);
+%! sol = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert (isfield (sol, "ie"));
+%! assert (sol.ie, [0;1]);
+%! assert (isfield (sol, "xe"));
+%! assert (isfield (sol, "ye"));
+%! assert (sol.x(end), 10, 1);
+%!test  # Events option, five output arguments
+%! opt = odeset ("Events", @ff);
+%! [t, y, te, ye, ie] = ode15i (@rob,[0 100], [1;0;0], [-1e-4;1e-4;0], opt);
+%! assert ([t(end), te', ie'], [10, 10, 10, 0, 1], [1, 0.2, 0.2, 0, 0]); 
+
+%!error  # Jacobian fun wrong dimension
+%! opt = odeset ("Jacobian", @jacwrong);
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!error  # Jacobian cell dense wrong dimension
+%!  DFDY = [-0.04, 1;
+%!           0.04, 1];
+%!  DFDYP = [-1,  0, 0;
+%!            0, -1, 0;
+%!            0,  0, 0];
+%! opt = odeset ("Jacobian", {DFDY, DFDYP});
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!error  # Jacobian cell sparse wrong dimension
+%!  DFDY = sparse ([-0.04, 1;
+%!                   0.04, 1]);
+%!  DFDYP = sparse ([-1,  0, 0;
+%!                    0, -1, 0;
+%!                    0,  0, 0]);
+%! opt = odeset ("Jacobian", {DFDY, DFDYP});
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!error  # Jacobian cell wrong number of matrices
+%! A = [1 2 3; 4 5 6; 7 8 9];
+%! opt = odeset ("Jacobian", {A,A,A});
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!error  # Jacobian single matrix
+%! opt = odeset ("Jacobian", [1 2 3; 4 5 6; 7 8 9]);
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!error  # Jacobian single matrix wrong dimension
+%! opt = odeset ("Jacobian", [1 2 3; 4 5 6]);
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!error  # Jacobian strange field
+%! opt = odeset ("Jacobian", "foo");
+%! [t, y] = ode15i (@rob,[0 4e6], [1;0;0], [-1e-4;1e-4;0], opt);
+%!function ydot = fun (t, y, yp)  
+%! ydot = [y - yp];
+%!endfunction
+%!error ode15i ();
+%!error ode15i (1);
+%!error ode15i (1, 1, 1);
+%!error ode15i (1, 1, 1);
+%!error ode15i (1, 1, 1, 1);
+%!error ode15i (1, 1, 1, 1, 1);
+%!error ode15i (1, 1, 1, 1, 1, 1);
+%!error ode15i (@fun, 1, 1, 1);
+%!error ode15i (@fun, [1, 1], 1, 1);
+%!error ode15i (@fun, [1, 2], [1], [1, 2]);
+%!error
+%!  opt = odeset ('RelTol', "foo");
+%!  [t, y] = ode15i (@fun, [0 2], [2], [2], opt);
+%!error
+%!  opt = odeset ('RelTol', [1, 2]);
+%!  [t, y] = ode15i (@fun, [0 2], [2], [2], opt);
+%!error
+%!  opt = odeset ('RelTol', -2);
+%!  [t, y] = ode15i (@fun, [0 2], [2], [2], opt);
+%!error
+%!  opt = odeset ('AbsTol', "foo");
+%!  [t, y] = ode15i (@fun, [0 2], [2], [2], opt);
+%!error
+%!  opt = odeset ('AbsTol', -1);
+%!  [t, y] = ode15i (@fun, [0 2], [2], [2], opt);
+%!error
+%!  opt = odeset ('AbsTol', [1, 1, 1]);
+%!  [t, y] = ode15i (@fun, [0 2], [2], [2], opt);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ode/ode15s.m	Tue Aug 23 03:19:11 2016 +0200
@@ -0,0 +1,686 @@
+## Copyright (C) 2016, Francesco Faccio <francesco.faccio@mail.polimi.it>
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {[@var{t}, @var{y}] =} ode15s (@var{fun}, @var{trange}, @var{y0})
+## @deftypefnx {} {[@var{t}, @var{y}] =} ode15s (@var{fun}, @var{trange}, @var{y0}, @var{ode_opt})
+## @deftypefnx {} {[@var{t}, @var{y}, @var{te}, @var{ye}, @var{ie}] =} ode15s (@dots{})
+## @deftypefnx {} {@var{solution} =} ode15s (@dots{})
+##
+## Solve a set of stiff Ordinary Differential Equations and stiff semi-explicit
+## Differential Algebraic Equations (DAEs) of index 1, with the variable-step,
+## variable order BDF (Backward Differentiation Formula) method, which
+## ranges from order 1 to 5.
+##
+## @var{fun} is a function handle, inline function, or string containing the
+## name of the function that defines the ODE: @code{f(@var{t},@var{y})}.
+## The function must accept two inputs where the first is time @var{t} and the
+## second is a column vector of unknowns @var{y}.
+##
+## @var{trange} specifies the time interval over which the ODE will be
+## evaluated.  Typically, it is a two-element vector specifying the initial and
+## final times (@code{[tinit, tfinal]}).  If there are more than two elements
+## then the solution will also be evaluated at these intermediate time.
+##
+## @var{init} contains the initial value for the unknowns.  If it is a row
+## vector then the solution @var{y} will be a matrix in which each column is
+## the solution for the corresponding initial value in @var{init}.
+##
+## The optional fourth argument @var{ode_opt} specifies non-default options to
+## the ODE solver.  It is a structure generated by @code{odeset}.
+##
+## The function typically returns two outputs.  Variable @var{t} is a
+## column vector and contains the times where the solution was found.  The
+## output @var{y} is a matrix in which each column refers to a different
+## unknown of the problem and each row corresponds to a time in @var{t}.
+##
+## The output can also be returned as a structure @var{solution} which
+## has field @var{x} containing the time where the solution was evaluated and
+## field @var{y} containing the solution matrix for the times in @var{x}.
+## Use @code{fieldnames (@var{solution})} to see the other fields and
+## additional information returned.
+##
+## If using the @qcode{"Events"} option then three additional outputs may
+## be returned.  @var{te} holds the time when an Event function returned a
+## zero.  @var{ye} holds the value of the solution at time @var{te}.  @var{ie}
+## contains an index indicating which Event function was triggered in the case
+## of multiple Event functions.
+##
+## This function can be called with two output arguments: @var{t} and @var{y}.
+## Variable @var{t} is a column vector and contains the time stamps, instead
+## @var{y} is a matrix in which each column refers to a different unknown of
+## the problem and the rows number is the same of @var{t} rows number so
+## that each row of @var{y} contains the values of all unknowns at the time
+## value contained in the corresponding row in @var{t}.
+##
+## Example: Solve the @nospell{Robetson}'s equations:
+## @example
+## @group
+## function res = robertsidae(@var{t}, @var{y})
+## res = [-0.04*@var{y}(1) + 1e4*@var{y}(2)*@var{y}(3);
+##         0.04*@var{y}(1) - 1e4*@var{y}(2)*@var{y}(3) - 3e7*@var{y}(2)^2;
+##         @var{y}(1) + @var{y}(2) + @var{y}(3) - 1];
+## endfunction
+## opt = odeset ("Mass", [1 0 0; 0 1 0; 0 0 0], "MStateDependence", "none");
+## [@var{t},@var{y}] = ode15s (@@robertsidae, [0 1e3], [1; 0; 0], opt);
+## @end group
+## @end example
+## @seealso{decic, odeset, odeget}
+## @end deftypefn
+
+function varargout = ode15s (fun, trange, y0, varargin)
+
+  solver = 'ode15s';  
+ 
+  if (nargin < 3)
+    print_usage ();
+  endif
+  
+  ## Check fun, trange, y0, yp0
+  fun = check_default_input (fun, trange, solver, y0);
+  
+  n = numel (y0);
+  
+  if (nargin > 3)
+   options = varargin{1};
+  else
+   options = odeset ();
+  endif
+
+  if (! isempty (options.Mass))
+    if (ischar (options.Mass))
+      try
+        options.Mass = str2func (options.Mass);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.Mass, "function_handle"))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Mass");
+      endif
+    endif
+  endif  
+
+  if (! isempty (options.Jacobian))
+    if (ischar (options.Jacobian))
+      try
+        options.Jacobian = str2func (options.Jacobian);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.Jacobian, "function_handle"))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+      endif
+    endif
+  endif
+
+  if (! isempty (options.OutputFcn))
+    if (ischar (options.OutputFcn))
+      try
+        options.OutputFcn = str2func (options.OutputFcn);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.OutputFcn, "function_handle"))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "OutputFcn");
+      endif
+    endif
+  endif
+
+  if (! isempty (options.Events))
+    if (ischar (options.Events))
+      try
+        options.Events = str2func (options.Events);
+      catch
+        warning (lasterr);
+      end_try_catch
+      if (! isa (options.Events, "function_handle"))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Events");
+      endif
+    endif
+  endif
+
+  persistent defaults   = [];
+  persistent classes    = [];
+  persistent attributes = [];
+
+  [defaults, classes, attributes] = odedefaults (n, trange(1),
+                                                 trange(end));
+
+  classes    = odeset (classes, 'Vectorized', {});
+  attributes = odeset (attributes, 'Jacobian', {}, 'Vectorized', {});
+
+  options = odemergeopts (options, defaults, classes, attributes, solver);
+
+  ## Mass
+
+  options.havemassfun    = false;
+  options.havestatedep   = false;
+  options.havetimedep    = false;
+  options.havemasssparse = false;
+
+  if (! isempty (options.Mass))
+    if (isa (options.Mass, "function_handle"))  
+      options.havemassfun = true;
+      if (nargin (options.Mass) == 2)
+        options.havestatedep = true;
+        M = options.Mass (trange(1), y0);
+        options.havemasssparse = issparse (M);
+        if (any (size (M) != [n n]) || ! isnumeric (M) || ! isreal (M))
+          error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Mass");
+        endif
+      elseif (nargin (options.Mass) == 1)
+        options.havetimedep = true;
+        M = options.Mass (trange(1));
+        options.havemasssparse = issparse (M);
+        if (any (size (M) != [n n]) || ! isnumeric (M) || ! isreal (M))
+          error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Mass");
+        endif
+      else
+        error ("Octave:invalid-input-arg",
+                [solver ": invalid value assigned to field '%s'"], "Mass");
+      endif
+    elseif (ismatrix (options.Mass))
+      options.havemasssparse = issparse (options.Mass);
+      if (any (size (options.Mass) != [n n]) ||
+          ! isnumeric (options.Mass) || ! isreal (options.Mass))
+        error ("Octave:invalid-input-arg",
+                [solver ": invalid value assigned to field '%s'"], "Mass");
+      endif
+    else 
+      error ("Octave:invalid-input-arg",
+              [solver ": invalid value assigned to field '%s'"], "Mass");
+    endif
+  endif
+
+
+  ## Jacobian
+  options.havejac       = false;
+  options.havejacsparse = false;
+  options.havejacfun    = false;
+
+  if (! isempty (options.Jacobian))
+    options.havejac = true;
+    if (isa (options.Jacobian, "function_handle"))  
+      options.havejacfun = true;
+      if (nargin (options.Jacobian) == 2)
+        [A] = options.Jacobian (trange(1), y0);
+        if (issparse (A))
+          options.havejacsparse = true;  ## Jac is sparse fun
+        endif
+        if (any (size (A) != [n n]) || ! isnumeric (A) || ! isreal (A))
+          error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+        endif
+      else
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+      endif
+    elseif (ismatrix (options.Jacobian))
+      if (issparse (options.Jacobian))
+        options.havejacsparse = true;            ## Jac is sparse matrix
+      endif
+      if (! issquare (options.Jacobian))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "Jacobian");
+      endif
+    else
+      error ("Octave:invalid-input-arg",
+             [solver ": invalid value assigned to field '%s'"], "Jacobian");
+    endif
+  endif
+
+
+  ## Derivative of M(t,y) for implicit problem not implemented yet
+  if (! isempty (options.Mass) && ! isempty (options.Jacobian))
+    if (options.MStateDependence != "none" || options.havestatedep == true)
+      options.havejac = false;
+      options.Jacobian = [];
+      warning ("ode15s:mass_state_dependent_provided",
+              ["with MStateDependence != 'none' an internal", ...
+               " approximation of Jacobian Matrix will be used.", ...
+               " Set MStateDependence equal to 'none' if you want ", ...
+               " to provide a constant or time-dependent Jacobian"]);
+    endif
+  endif
+  
+  ## Use sparse methods only if all matrices are sparse
+  if (! options.havemasssparse)
+    options.havejacsparse = false; 
+  endif       
+  
+  ## If Mass or Jacobian is fun, then new Jacobian is fun  
+  if (options.havejac)
+    if (options.havejacfun || options.havetimedep)
+      options.Jacobian = @ (t, y, yp) wrapjacfun (t, y, yp,
+                                                  options.Jacobian,
+                                                  options.Mass,
+                                                  options.havetimedep,
+                                                  options.havejacfun);
+      options.havejacfun = true;
+    else   ## All matrices are constant
+      options.Jacobian = {[- options.Jacobian], [options.Mass]};
+           
+    endif
+  endif
+
+
+
+  ## Abstol and Reltol
+
+  options.haveabstolvec = false;
+
+  if (numel (options.AbsTol) != 1 && numel (options.AbsTol) != n)
+    error ("Octave:invalid-input-arg",
+           [solver ": invalid value assigned to field '%s'"], "AbsTol");
+  
+  elseif (numel (options.AbsTol) == n)
+    options.haveabstolvec = true;
+  endif
+
+  ## Stats
+  options.havestats = false;    
+  if (strcmp (options.Stats, "on"))
+    options.havestats = true;    
+  endif
+
+  ## Don't use Refine when the output is a structure
+  if (nargout == 1)
+    options.Refine = 1;
+  endif
+
+  ## OutputFcn and OutputSel
+  if (isempty (options.OutputFcn) && nargout == 0)
+    options.OutputFcn = @odeplot;
+    options.haveoutputfunction = true;
+  else
+    options.haveoutputfunction = ! isempty (options.OutputFcn);
+  endif
+  
+  options.haveoutputselection = ! isempty (options.OutputSel);
+  if (options.haveoutputselection)
+    options.OutputSel = options.OutputSel - 1;
+  endif
+
+  ## Events
+  options.haveeventfunction = ! isempty (options.Events);
+
+  yp0 = options.InitialSlope;
+
+
+  [t, y, te, ye, ie] = __ode15__ (@ (t, y, yp) wrap (t, y, yp, options.Mass,
+                                                     options.havetimedep,
+                                                     options.havestatedep,
+                                                     fun),
+                                  trange, y0, yp0, options);
+
+  if (nargout == 2)
+    varargout{1} = t;
+    varargout{2} = y;
+  elseif (nargout == 1)
+    varargout{1}.x = t;    # Time stamps are saved in field x
+    varargout{1}.y = y;    # Results are saved in field y
+    varargout{1}.solver = solver; 
+    if (options.haveeventfunction)
+      varargout{1}.xe = te;  # Time info when an event occurred
+      varargout{1}.ye = ye;  # Results when an event occurred
+      varargout{1}.ie = ie;  # Index info which event occurred
+    endif
+  elseif (nargout == 5)
+    varargout = cell (1,5);
+    varargout{1} = t;
+    varargout{2} = y;
+    if (options.haveeventfunction)
+      varargout{3} = te;  # Time info when an event occurred
+      varargout{4} = ye;  # Results when an event occurred
+      varargout{5} = ie;  # Index info which event occurred
+    endif
+  endif
+
+endfunction
+
+function res = wrap (t, y, yp, Mass, havetimedep, havestatedep, fun)
+
+  if (! isempty (Mass) && havestatedep)  
+    res = Mass (t, y) * yp - fun (t, y);
+  elseif (! isempty (Mass) && havetimedep)
+    res = Mass (t) * yp - fun (t, y);
+  elseif (! isempty (Mass))
+    res = Mass * yp - fun (t, y);
+  else
+    res = yp - fun (t, y);
+  endif
+
+endfunction
+
+function [jac, jact] = wrapjacfun (t, y, yp, Jac, Mass,
+                                   havetimedep, havejacfun) 
+  if (havejacfun)
+    jac = - Jac (t, y);
+  else
+    jac = - Jac;
+  endif
+
+  if (! isempty (Mass) && havetimedep) 
+    jact = Mass (t);
+  elseif (! isempty (Mass))
+    jact = Mass;
+  else
+    jact = speye (numel (y));
+  endif
+  
+endfunction
+
+
+%!demo
+%! 
+%! ##Solve Robertson's equations with ode15s 
+%! fun = @ (t, y) [-0.04*y(1) + 1e4*y(2).*y(3);
+%!                  0.04*y(1) - 1e4*y(2).*y(3) - 3e7*y(2).^2;
+%!                  y(1) + y(2) + y(3) - 1 ];
+%!
+%! y0 = [1; 0; 0];
+%! tspan = [0 4*logspace(-6, 6)];
+%! M = [1 0 0; 0 1 0; 0 0 0];
+%!  
+%! options = odeset ('RelTol', 1e-4, 'AbsTol', [1e-6 1e-10 1e-6],
+%!                   'MStateDependence', 'none', 'Mass', M);
+%!
+%! [t, y] = ode15s (fun, tspan, y0, options);
+%!
+%! y (:,2) = 1e4 * y (:,2);
+%! figure (2);
+%! semilogx (t, y, 'o')
+%! xlabel ('time');
+%! ylabel ('species concentration');
+%! title ('Robertson DAE problem with a Conservation Law');
+%! legend ('y1', 'y2', 'y3');
+
+%!function ydot = fpol (t, y)  # The Van der Pol
+%! ydot = [y(2); (1 - y(1)^2) * y(2) - y(1)];
+%!endfunction
+%!function ref = fref ()       # The computed reference sol
+%! ref = [0.32331666704577, -1.83297456798624];
+%!endfunction
+%!function jac = fjac (t, y)  # its Jacobian
+%! jac = [0, 1; -1 - 2 * y(1) * y(2), 1 - y(1)^2];
+%!endfunction
+%!function jac = fjcc (t, y)  # sparse type
+%! jac = sparse ([0, 1; -1 - 2 * y(1) * y(2), 1 - y(1)^2]);
+%!endfunction
+%!function mas = fmas (t, y)
+%! mas = [1, 0; 0, 1];             # Dummy mass matrix for tests
+%!endfunction
+%!function mas = fmsa (t, y)
+%! mas = sparse ([1, 0; 0, 1]);    # A sparse dummy matrix
+%!endfunction
+%!function res = rob (t, y)
+%! res = [-0.04*y(1) + 1e4*y(2).*y(3);
+%!         0.04*y(1) - 1e4*y(2).*y(3) - 3e7*y(2).^2;
+%!         y(1) + y(2) + y(3) - 1 ];
+%!endfunction
+%!
+%!function refrob = frefrob()
+%! refrob = [100, 0.617234887614937, 0.000006153591397, 0.382758958793666];
+%!endfunction
+%!function [val, isterminal, direction] = feve (t, y)
+%!  isterminal = [0 1];
+%!  if (t < 1e1)
+%!    val = [-1, -2];
+%!  else
+%!    val = [1 3];
+%!  endif
+%!  
+%!  direction = [1 0];
+%!endfunction
+%!function masrob = massdensefunstate (t, y)
+%! masrob = [1 0 0; 0 1 0; 0 0 0];     
+%!endfunction
+%!function masrob = masssparsefunstate (t, y)
+%! masrob = sparse([1 0 0; 0 1 0; 0 0 0]);     
+%!endfunction
+%!function masrob = massdensefuntime (t)
+%! masrob = [1 0 0; 0 1 0; 0 0 0];     
+%!endfunction
+%!function masrob = masssparsefuntime (t)
+%! masrob = sparse([1 0 0; 0 1 0; 0 0 0]);     
+%!endfunction
+%!function jac = jacfundense (t, y)
+%!  jac = [-0.04,           1e4*y(3),  1e4*y(2);
+%!           0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!              1,                  1,         1];
+%!endfunction
+%!function jac = jacfunsparse (t, y)
+%!  jac = sparse([-0.04,           1e4*y(3),  1e4*y(2);
+%!                 0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!                    1,                  1,         1]);
+%!endfunction
+
+
+
+%!test
+%! opt = odeset ("MStateDependence", "none", 
+%!                "Mass", [1 0 0; 0 1 0; 0 0 0]);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! opt = odeset ("MStateDependence", "none", 
+%!                "Mass", sparse([1 0 0; 0 1 0; 0 0 0]));
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @massdensefunstate);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @masssparsefunstate);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! opt = odeset ("MStateDependence", "none", 
+%!                "Mass", 'massdensefuntime');
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);  
+%!test 
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", [1 0 0; 0 1 0; 0 0 0],
+%!                "Jacobian", 'jacfundense');
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! opt = odeset ("MStateDependence", "none", 
+%!                "Mass", sparse([1 0 0; 0 1 0; 0 0 0]),
+%!                "Jacobian", @jacfundense); 
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test              
+%! warning ("off", "ode15s:mass_state_dependent_provided", "local");
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @massdensefunstate,
+%!                "Jacobian", @jacfundense);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! warning ("off", "ode15s:mass_state_dependent_provided", "local");
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @masssparsefunstate,
+%!                "Jacobian", @jacfundense);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @massdensefuntime,
+%!                "Jacobian", @jacfundense);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);    
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", 'masssparsefuntime',
+%!                "Jacobian", 'jacfundense');
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);  
+%!test              
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", [1 0 0; 0 1 0; 0 0 0],
+%!                "Jacobian", @jacfunsparse);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", sparse([1 0 0; 0 1 0; 0 0 0]),
+%!               "Jacobian", @jacfunsparse); 
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3); 
+%!test             
+%! warning ("off", "ode15s:mass_state_dependent_provided", "local");
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @massdensefunstate,
+%!                "Jacobian", @jacfunsparse);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%! warning ("off", "ode15s:mass_state_dependent_provided", "local");
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @masssparsefunstate,
+%!                "Jacobian", @jacfunsparse);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @massdensefuntime,
+%!                "Jacobian", @jacfunsparse);  
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3); 
+%!test 
+%!  opt = odeset ("MStateDependence", "none", 
+%!                "Mass", @masssparsefuntime,
+%!                "Jacobian", @jacfunsparse);
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), y(end,:)], frefrob, 1e-3);
+%!test  # two output arguments
+%! [t, y] = ode15s (@fpol, [0 2], [2 0]);
+%! assert ([t(end), y(end,:)], [2, fref], 1e-2);
+%!test  # anonymous function instead of real function
+%! fvdb = @(t,y) [y(2); (1 - y(1)^2) * y(2) - y(1)];
+%! [t, y] = ode15s (fvdb, [0 2], [2 0]);
+%! assert ([t(end), y(end,:)], [2, fref], 1e-2);
+%!test  # Solve another anonymous function below zero
+%! ref = [0, 14.77810590694212];
+%! [t, y] = ode15s (@(t,y) y, [-2 0], 2);
+%! assert ([t(end), y(end,:)], ref, 5e-2);
+%!test  # InitialStep option
+%! opt = odeset ("InitialStep", 1e-8);
+%! [t, y] = ode15s (@fpol, [0 0.2], [2 0], opt);
+%! assert ([t(2)-t(1)], [1e-8], 1e-9);
+%!test  # MaxStep option
+%! opt = odeset ("MaxStep", 1e-3);
+%! sol = ode15s (@fpol, [0 0.2], [2 0], opt);
+%! assert ([sol.x(5)-sol.x(4)], [1e-3], 1e-3);
+%!test  # Solve in backward direction starting at t=0
+%! ref = [-1.205364552835178, 0.951542399860817];
+%! sol = ode15s (@fpol, [0 -2], [2 0]);
+%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 5e-3);
+%!test  # Solve in backward direction starting at t=2
+%! ref = [-1.205364552835178, 0.951542399860817];
+%! sol = ode15s (@fpol, [2 0 -2], fref);
+%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 3e-2);
+%!test  # Solve another anonymous function in backward direction
+%! ref = [-1, 0.367879437558975];
+%! sol = ode15s (@(t,y) y, [0 -1], 1);
+%! assert ([sol.x(end), sol.y(end,:)], ref, 1e-2);
+%!test  # Solve another anonymous function below zero
+%! ref = [0, 14.77810590694212];
+%! sol = ode15s (@(t,y) y, [-2 0], 2);
+%! assert ([sol.x(end), sol.y(end,:)], ref, 5e-2);
+%!test  # Solve in backward direction starting at t=0 with MaxStep option
+%! ref = [-1.205364552835178, 0.951542399860817];
+%! opt = odeset ("MaxStep", 1e-3);
+%! sol = ode15s (@fpol, [0 -2], [2 0], opt);
+%! assert ([abs(sol.x(8)-sol.x(7))], [1e-3], 1e-3);
+%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 1e-3);
+%!test  # AbsTol option
+%! opt = odeset ("AbsTol", 1e-5);
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 4e-3);
+%!test  # AbsTol and RelTol option
+%! opt = odeset ("AbsTol", 1e-8, "RelTol", 1e-8);
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3);
+%!test  # RelTol option -- higher accuracy
+%! opt = odeset ("RelTol", 1e-8);
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-4);
+%!test  # Mass option as function
+%! opt = odeset ("Mass", @fmas, "MStateDependence", "none");
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%!test  # Mass option as matrix
+%! opt = odeset ("Mass", eye (2,2), "MStateDependence", "none");
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%!test  # Mass option as sparse matrix
+%! opt = odeset ("Mass", sparse (eye (2,2)), "MStateDependence", "none");
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%!test  # Mass option as function and sparse matrix
+%! opt = odeset ("Mass", 'fmsa', "MStateDependence", "none");
+%! sol = ode15s (@fpol, [0 2], [2 0], opt);
+%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%!test  # Refine
+%! opt2 = odeset ("Refine", 3, "Mass", @massdensefunstate,
+%!                "MStateDependence", "none");
+%! opt1 = odeset ("Mass", @massdensefunstate, "MStateDependence", "none");
+%! [t, y] = ode15s (@rob,[0 100], [1;0;0], opt1);
+%! [t2, y2] = ode15s (@rob,[0 100], [1;0;0], opt2);
+%! assert ([numel(t2)], numel(t)*3, 3);
+%!test  # Refine ignored if numel (trange) > 2
+%! opt2 = odeset ("Refine", 3, "Mass", 'massdensefunstate',
+%!                "MStateDependence", "none");
+%! opt1 = odeset ("Mass", @massdensefunstate, "MStateDependence", "none");
+%! [t, y] = ode15s ('rob',[0 10 100], [1;0;0], opt1);
+%! [t2, y2] = ode15s ('rob',[0 10 100], [1;0;0], opt2);
+%! assert ([numel(t2)], numel(t));
+%!test  # Events option add further elements in sol
+%! opt = odeset ("Events", @feve, "Mass", @massdensefunstate,
+%!               "MStateDependence", "none");
+%! sol = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert (isfield (sol, "ie"));
+%! assert (sol.ie, [0;1]);
+%! assert (isfield (sol, "xe"));
+%! assert (isfield (sol, "ye"));
+%! assert (sol.x(end), 10, 1);
+%!test  # Events option, five output arguments
+%! opt = odeset ("Events", @feve, "Mass", @massdensefunstate,
+%!               "MStateDependence", "none");
+%! [t, y, te, ye, ie] = ode15s (@rob,[0 100], [1;0;0], opt);
+%! assert ([t(end), te', ie'], [10, 10, 10, 0, 1], [1, 0.5, 0.5, 0, 0]); 
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ode/private/check_default_input.m	Tue Aug 23 03:19:11 2016 +0200
@@ -0,0 +1,65 @@
+## Copyright (C) 2016, Francesco Faccio <francesco.faccio@mail.polimi.it>
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+function [fun] = check_default_input (fun, trange, solver, varargin);
+
+  ## Check fun
+  validateattributes (fun, {"function_handle", "char"}, {}, solver, "fun");
+
+  if (! (nargin (fun) == nargin - 2))
+    error ("Octave:invalid-input-arg",
+           [solver ": invalid value assigned to field '%s'"], "fun");
+  endif
+
+  if (ischar (fun))
+    try
+      fun = str2func (fun);
+    catch
+      warning (lasterr);
+    end_try_catch
+  endif
+  if (! isa (fun, "function_handle"))
+    error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "fun");
+  endif
+  
+  ## Check trange 
+  validateattributes (trange, {"float"}, {"vector", "real"}, solver, "trange");
+  
+  if (numel (trange) < 2)
+       error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "trange");
+  elseif (! ((all (diff (trange) > 0)) || all (diff (-trange) > 0)))
+        error ("Octave:invalid-input-arg",
+               [solver ": invalid value assigned to field '%s'"], "trange");
+  endif
+
+  ## Check y0 and yp0
+  y0 = varargin{1};
+
+  if (nargin == 5)
+    yp0 = varargin{2};
+    n = numel (feval (fun, trange(1), y0, yp0));
+    validateattributes (yp0, {"float"}, {"numel", n}, solver, "yp0");
+  else
+    n = numel (feval (fun, trange (1), y0));
+  endif
+
+  validateattributes (y0, {"float"}, {"numel", n}, solver, "y0");
+ 
+endfunction