Tighten input sanity checks of various MEX files

Note that the unitary test in lyapunov_solver.m that checks sparse matrix input
had to be removed. Previously, this test was passing by chance (because the
sparse test matrices had actually no zero element, hence the internal double
float storage was the same as in the dense case). Now it consistently fails
with the additional checks in disclyap_fast MEX.
trustregion
Sébastien Villemot 2022-03-18 18:18:24 +01:00
parent 4f6d8a198a
commit d5472d2338
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
19 changed files with 235 additions and 154 deletions

View File

@ -1,6 +1,6 @@
/*
* Copyright © 2004-2011 Ondra Kamenik
* Copyright © 2019 Dynare Team
* Copyright © 2019-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -125,8 +125,8 @@ Vector::Vector(mxArray *p)
: len{static_cast<int>(mxGetNumberOfElements(p))},
data{mxGetPr(p)}, destroy{false}
{
if (!mxIsDouble(p))
throw SYLV_MES_EXCEPTION("This is not a MATLAB array of doubles.");
if (!mxIsDouble(p) || mxIsComplex(p) || mxIsSparse(p))
throw SYLV_MES_EXCEPTION("This is not a dense array of real doubles.");
}
#endif

View File

@ -23,7 +23,7 @@ function P=lyapunov_solver(T,R,Q,DynareOptions) % --*-- Unitary tests --*--
% Square-root solver for discrete-time Lyapunov equations (requires Matlab System Control toolbox
% or Octave control package)
% Copyright (C) 2016-2021 Dynare Team
% Copyright (C) 2016-2022 Dynare Team
%
% This file is part of Dynare.
%
@ -136,72 +136,51 @@ end
%$ t(4) = 0;
%$ end
%$
%$ % Standard with sparse matrix
%$ try
%$ Pstar5_small = lyapunov_solver(sparse(T_small),sparse(R_small),sparse(Q_small),options_);
%$ Pstar5_large = lyapunov_solver(sparse(T_large),sparse(R_large),sparse(Q_large),options_);
%$ t(5) = 1;
%$ catch
%$ t(5) = 0;
%$ end
%$
%$ % Test the results.
%$
%$ if max(max(abs(Pstar1_small-Pstar2_small)))>1e-8
%$ t(6) = 0;
%$ t(5) = 0;
%$ else
%$ t(6) = 1;
%$ t(5) = 1;
%$ end
%$
%$ if (isoctave && user_has_octave_forge_package('control')) || (~isoctave && user_has_matlab_license('control_toolbox'))
%$ if max(max(abs(Pstar1_small-Pstar3_small)))>1e-8
%$ t(7) = 0;
%$ t(6) = 0;
%$ else
%$ t(7) = 1;
%$ t(6) = 1;
%$ end
%$ else
%$ t(6) = 1;
%$ end
%$
%$ if max(max(abs(Pstar1_small-Pstar4_small)))>1e-8
%$ t(7) = 0;
%$ else
%$ t(7) = 1;
%$ end
%$
%$ if max(max(abs(Pstar1_small-Pstar4_small)))>1e-8
%$ if max(max(abs(Pstar1_large-Pstar2_large)))>2e-8
%$ t(8) = 0;
%$ else
%$ t(8) = 1;
%$ end
%$
%$ if max(max(abs(Pstar1_small-Pstar5_small)))>1e-8
%$ t(9) = 0;
%$ if (isoctave && user_has_octave_forge_package('control')) || (~isoctave && user_has_matlab_license('control_toolbox'))
%$ if max(max(abs(Pstar1_large-Pstar3_large)))>1e-8
%$ t(9) = 0;
%$ else
%$ t(9) = 1;
%$ end
%$ else
%$ t(9) = 1;
%$ end
%$
%$ if max(max(abs(Pstar1_large-Pstar2_large)))>2e-8
%$
%$ if max(max(abs(Pstar1_large-Pstar4_large)))>2e-8
%$ t(10) = 0;
%$ else
%$ t(10) = 1;
%$ end
%$
%$ if (isoctave && user_has_octave_forge_package('control')) || (~isoctave && user_has_matlab_license('control_toolbox'))
%$ if max(max(abs(Pstar1_large-Pstar3_large)))>1e-8
%$ t(11) = 0;
%$ else
%$ t(11) = 1;
%$ end
%$ else
%$ t(11) = 1;
%$ end
%$
%$ if max(max(abs(Pstar1_large-Pstar4_large)))>2e-8
%$ t(12) = 0;
%$ else
%$ t(12) = 1;
%$ end
%$
%$ if max(max(abs(Pstar1_large-Pstar5_large)))>2e-8
%$ t(13) = 0;
%$ else
%$ t(13) = 1;
%$ end
%$
%$ T = all(t);
%@eof:1

View File

@ -1,4 +1,4 @@
! Copyright © 2019-2021 Dynare Team
! Copyright © 2019-2022 Dynare Team
!
! This file is part of Dynare.
!
@ -51,8 +51,9 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
call mexErrMsgTxt("First argument (function) should be a string or a function handle")
end if
if (.not. (mxIsDouble(prhs(2)) .and. (mxGetM(prhs(2)) == 1 .or. mxGetN(prhs(2)) == 1))) then
call mexErrMsgTxt("Second argument (initial guess) should be a real vector")
if (.not. (mxIsDouble(prhs(2)) .and. (mxGetM(prhs(2)) == 1 .or. mxGetN(prhs(2)) == 1)) &
.or. mxIsComplex(prhs(2)) .or. mxIsSparse(prhs(2))) then
call mexErrMsgTxt("Second argument (initial guess) should be a real dense vector")
end if
if (.not. (mxIsScalar(prhs(3)) .and. mxIsNumeric(prhs(3)))) then

View File

@ -20,7 +20,7 @@
! This is a Fortran translation of a code originally written by Joe Pearlman
! and Alejandro Justiniano.
! Copyright © 2020-2021 Dynare Team
! Copyright © 2020-2022 Dynare Team
!
! This file is part of Dynare.
!
@ -64,10 +64,10 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
end if
n = mxGetM(prhs(1))
if (.not. mxIsDouble(prhs(1)) .or. mxIsComplex(prhs(1)) &
.or. .not. mxIsDouble(prhs(2)) .or. mxIsComplex(prhs(2)) &
if (.not. mxIsDouble(prhs(1)) .or. mxIsComplex(prhs(1)) .or. mxIsSparse(prhs(1)) &
.or. .not. mxIsDouble(prhs(2)) .or. mxIsComplex(prhs(2)) .or. mxIsSparse(prhs(2)) &
.or. mxGetN(prhs(1)) /= n .or. mxGetM(prhs(2)) /= n .or. mxGetN(prhs(2)) /= n) then
call mexErrMsgTxt("disclyap_fast: first two arguments should be real matrices of the same dimension")
call mexErrMsgTxt("disclyap_fast: first two arguments should be real dense matrices of the same dimension")
end if
if (.not. (mxIsScalar(prhs(3)) .and. mxIsNumeric(prhs(3)))) then

View File

@ -1,6 +1,6 @@
/*
* Copyright © 2005-2011 Ondra Kamenik
* Copyright © 2019-2020 Dynare Team
* Copyright © 2019-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -54,11 +54,24 @@ extern "C" {
if (nhrs != 5 || nlhs > 2 || nlhs < 1)
mexErrMsgTxt("Gensylv: Must have exactly 5 input args and either 1 or 2 output args.");
if (!(mxIsScalar(prhs[0]) && mxIsNumeric(prhs[0])))
mexErrMsgTxt("First argument should be a numeric scalar");
auto order = static_cast<int>(mxGetScalar(prhs[0]));
const mxArray *const A = prhs[1];
const mxArray *const B = prhs[2];
const mxArray *const C = prhs[3];
const mxArray *const D = prhs[4];
if (!mxIsDouble(A) || mxIsComplex(A) || mxIsSparse(A))
mexErrMsgTxt("Matrix A must be a real dense matrix.");
if (!mxIsDouble(B) || mxIsComplex(B) || mxIsSparse(B))
mexErrMsgTxt("Matrix B must be a real dense matrix.");
if (!mxIsDouble(C) || mxIsComplex(C) || mxIsSparse(C))
mexErrMsgTxt("Matrix C must be a real dense matrix.");
if (!mxIsDouble(D) || mxIsComplex(D) || mxIsSparse(D))
mexErrMsgTxt("Matrix D must be a real dense matrix.");
const mwSize *const Adims = mxGetDimensions(A);
const mwSize *const Bdims = mxGetDimensions(B);
const mwSize *const Cdims = mxGetDimensions(C);

View File

@ -77,37 +77,39 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
if (nrhs /= 12) then
call mexErrMsgTxt("Must have exactly 12 inputs")
end if
if (.not. (mxIsScalar(order_mx)) .and. mxIsNumeric(order_mx)) then
if (.not. (mxIsScalar(order_mx) .and. mxIsNumeric(order_mx))) then
call mexErrMsgTxt("1st argument (order) should be a numeric scalar")
end if
if (.not. (mxIsScalar(nstatic_mx)) .and. mxIsNumeric(nstatic_mx)) then
if (.not. (mxIsScalar(nstatic_mx) .and. mxIsNumeric(nstatic_mx))) then
call mexErrMsgTxt("2nd argument (nstat) should be a numeric scalar")
end if
if (.not. (mxIsScalar(npred_mx)) .and. mxIsNumeric(npred_mx)) then
if (.not. (mxIsScalar(npred_mx) .and. mxIsNumeric(npred_mx))) then
call mexErrMsgTxt("3rd argument (npred) should be a numeric scalar")
end if
if (.not. (mxIsScalar(nboth_mx)) .and. mxIsNumeric(nboth_mx)) then
if (.not. (mxIsScalar(nboth_mx) .and. mxIsNumeric(nboth_mx))) then
call mexErrMsgTxt("4th argument (nboth) should be a numeric scalar")
end if
if (.not. (mxIsScalar(nfwrd_mx)) .and. mxIsNumeric(nfwrd_mx)) then
if (.not. (mxIsScalar(nfwrd_mx) .and. mxIsNumeric(nfwrd_mx))) then
call mexErrMsgTxt("5th argument (nforw) should be a numeric scalar")
end if
if (.not. (mxIsScalar(nexog_mx)) .and. mxIsNumeric(nexog_mx)) then
if (.not. (mxIsScalar(nexog_mx) .and. mxIsNumeric(nexog_mx))) then
call mexErrMsgTxt("6th argument (nexog) should be a numeric scalar")
end if
if (.not. (mxIsScalar(order_moment_mx)) .and. mxIsNumeric(order_moment_mx)) then
if (.not. (mxIsScalar(order_moment_mx) .and. mxIsNumeric(order_moment_mx))) then
call mexErrMsgTxt("7th argument (order_moment) should be a numeric scalar")
end if
if (.not. (mxIsScalar(nburn_mx)) .and. mxIsNumeric(nburn_mx)) then
if (.not. (mxIsScalar(nburn_mx) .and. mxIsNumeric(nburn_mx))) then
call mexErrMsgTxt("8th argument (nburn) should be a numeric scalar")
end if
if (.not. (mxIsDouble(yhat_start_mx) .and. (mxGetM(yhat_start_mx) == 1 .or. mxGetN(yhat_start_mx) == 1))) then
call mexErrMsgTxt("9th argument (yhat_start) should be a real vector")
if (.not. (mxIsDouble(yhat_start_mx) .and. (mxGetM(yhat_start_mx) == 1 .or. mxGetN(yhat_start_mx) == 1)) &
.or. mxIsComplex(yhat_start_mx) .or. mxIsSparse(yhat_start_mx)) then
call mexErrMsgTxt("9th argument (yhat_start) should be a real dense vector")
end if
if (.not. (mxIsDouble(shocks_mx))) then
call mexErrMsgTxt("10th argument (shocks) should be a real matrix")
if (.not. (mxIsDouble(shocks_mx)) .or. mxIsComplex(shocks_mx) .or. mxIsSparse(shocks_mx)) then
call mexErrMsgTxt("10th argument (shocks) should be a real dense matrix")
end if
if (.not. (mxIsDouble(ysteady_mx) .and. (mxGetM(ysteady_mx) == 1 .or. mxGetN(ysteady_mx) == 1))) then
if (.not. (mxIsDouble(ysteady_mx) .and. (mxGetM(ysteady_mx) == 1 .or. mxGetN(ysteady_mx) == 1)) &
.or. mxIsComplex(ysteady_mx) .or. mxIsSparse(ysteady_mx)) then
call mexErrMsgTxt("11th argument (ysteady) should be a real vector")
end if
if (.not. mxIsStruct(dr_mx)) then

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2008-2021 Dynare Team
* Copyright © 2008-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -133,15 +133,16 @@ extern "C" {
std::string fname{mxArrayToString(fname_mx)};
const mxArray *params_mx = mxGetField(M_mx, 0, "params");
if (!(params_mx && mxIsDouble(params_mx)))
mexErrMsgTxt("M_.params should be a double precision array");
if (!(params_mx && mxIsDouble(params_mx) && !mxIsComplex(params_mx) && !mxIsSparse(params_mx)))
mexErrMsgTxt("M_.params should be a real dense array");
Vector modParams{ConstVector{params_mx}};
if (!modParams.isFinite())
mexErrMsgTxt("M_.params contains NaN or Inf");
const mxArray *sigma_e_mx = mxGetField(M_mx, 0, "Sigma_e");
if (!(sigma_e_mx && mxIsDouble(sigma_e_mx) && mxGetM(sigma_e_mx) == mxGetN(sigma_e_mx)))
mexErrMsgTxt("M_.Sigma_e should be a double precision square matrix");
if (!(sigma_e_mx && mxIsDouble(sigma_e_mx) && !mxIsComplex(sigma_e_mx) && !mxIsSparse(sigma_e_mx)
&& mxGetM(sigma_e_mx) == mxGetN(sigma_e_mx)))
mexErrMsgTxt("M_.Sigma_e should be a real dense square matrix");
TwoDMatrix vCov{ConstTwoDMatrix{sigma_e_mx}};
if (!vCov.isFinite())
mexErrMsgTxt("M_.Sigma_e contains NaN or Inf");
@ -156,13 +157,16 @@ extern "C" {
const int nPar = get_int_field(M_mx, "param_nbr");
const mxArray *lead_lag_incidence_mx = mxGetField(M_mx, 0, "lead_lag_incidence");
if (!(lead_lag_incidence_mx && mxIsDouble(lead_lag_incidence_mx) && mxGetM(lead_lag_incidence_mx) == 3
if (!(lead_lag_incidence_mx && mxIsDouble(lead_lag_incidence_mx)
&& !mxIsComplex(lead_lag_incidence_mx) && !mxIsSparse(lead_lag_incidence_mx)
&& mxGetM(lead_lag_incidence_mx) == 3
&& mxGetN(lead_lag_incidence_mx) == static_cast<size_t>(nEndo)))
mexErrMsgTxt("M_.lead_lag_incidence should be a double precision matrix with 3 rows and M_.endo_nbr columns");
mexErrMsgTxt("M_.lead_lag_incidence should be a real dense matrix with 3 rows and M_.endo_nbr columns");
ConstTwoDMatrix llincidence{lead_lag_incidence_mx};
const mxArray *nnzderivatives_mx = mxGetField(M_mx, 0, "NNZDerivatives");
if (!(nnzderivatives_mx && mxIsDouble(nnzderivatives_mx)))
if (!(nnzderivatives_mx && mxIsDouble(nnzderivatives_mx) && !mxIsComplex(nnzderivatives_mx)
&& !mxIsSparse(nnzderivatives_mx)))
mexErrMsgTxt("M_.NNZDerivatives should be a double precision array");
ConstVector NNZD{nnzderivatives_mx};
if (NNZD.length() < kOrder || NNZD[kOrder-1] == -1)
@ -179,21 +183,24 @@ extern "C" {
std::vector<std::string> exoNames = DynareMxArrayToString(exo_names_mx);
const mxArray *dynamic_tmp_nbr_mx = mxGetField(M_mx, 0, "dynamic_tmp_nbr");
if (!(dynamic_tmp_nbr_mx && mxIsDouble(dynamic_tmp_nbr_mx) && mxGetNumberOfElements(dynamic_tmp_nbr_mx) >= static_cast<size_t>(kOrder+1)))
mexErrMsgTxt("M_.dynamic_tmp_nbr should be a double precision array with strictly more elements than the order of derivation");
if (!(dynamic_tmp_nbr_mx && mxIsDouble(dynamic_tmp_nbr_mx) && !mxIsComplex(dynamic_tmp_nbr_mx)
&& !mxIsSparse(dynamic_tmp_nbr_mx)
&& mxGetNumberOfElements(dynamic_tmp_nbr_mx) >= static_cast<size_t>(kOrder+1)))
mexErrMsgTxt("M_.dynamic_tmp_nbr should be a real dense array with strictly more elements than the order of derivation");
int ntt = std::accumulate(mxGetPr(dynamic_tmp_nbr_mx), mxGetPr(dynamic_tmp_nbr_mx)+kOrder+1, 0);
// Extract various fields from dr
const mxArray *ys_mx = mxGetField(dr_mx, 0, "ys"); // and not in order of dr.order_var
if (!(ys_mx && mxIsDouble(ys_mx)))
mexErrMsgTxt("dr.ys should be a double precision array");
if (!(ys_mx && mxIsDouble(ys_mx) && !mxIsComplex(ys_mx) && !mxIsSparse(ys_mx)))
mexErrMsgTxt("dr.ys should be a real dense array");
Vector ySteady{ConstVector{ys_mx}};
if (!ySteady.isFinite())
mexErrMsgTxt("dr.ys contains NaN or Inf");
const mxArray *order_var_mx = mxGetField(dr_mx, 0, "order_var");
if (!(order_var_mx && mxIsDouble(order_var_mx) && mxGetNumberOfElements(order_var_mx) == static_cast<size_t>(nEndo)))
mexErrMsgTxt("dr.order_var should be a double precision array of M_.endo_nbr elements");
if (!(order_var_mx && mxIsDouble(order_var_mx) && !mxIsComplex(order_var_mx) && !mxIsSparse(order_var_mx)
&& mxGetNumberOfElements(order_var_mx) == static_cast<size_t>(nEndo)))
mexErrMsgTxt("dr.order_var should be a real dense array of M_.endo_nbr elements");
std::vector<int> dr_order(nEndo);
std::transform(mxGetPr(order_var_mx), mxGetPr(order_var_mx)+nEndo, dr_order.begin(),
[](double x) { return static_cast<int>(x)-1; });

View File

@ -1,4 +1,4 @@
! Copyright © 2021 Dynare Team
! Copyright © 2021-2022 Dynare Team
!
! This file is part of Dynare.
!
@ -85,14 +85,16 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
if (.not. (mxIsScalar(nexog_mx)) .and. mxIsNumeric(nexog_mx)) then
call mexErrMsgTxt("6th argument (nexog) should be a numeric scalar")
end if
if (.not. (mxIsDouble(ystart_mx) .and. (mxGetM(ystart_mx) == 1 .or. mxGetN(ystart_mx) == 1))) then
call mexErrMsgTxt("7th argument (ystart) should be a real vector")
if (.not. (mxIsDouble(ystart_mx) .and. (mxGetM(ystart_mx) == 1 .or. mxGetN(ystart_mx) == 1)) &
.or. mxIsComplex(ystart_mx) .or. mxIsSparse(ystart_mx)) then
call mexErrMsgTxt("7th argument (ystart) should be a real dense vector")
end if
if (.not. (mxIsDouble(shocks_mx))) then
call mexErrMsgTxt("8th argument (shocks) should be a real matrix")
if (.not. mxIsDouble(shocks_mx) .or. mxIsComplex(shocks_mx) .or. mxIsSparse(shocks_mx)) then
call mexErrMsgTxt("8th argument (shocks) should be a real dense matrix")
end if
if (.not. (mxIsDouble(ysteady_mx) .and. (mxGetM(ysteady_mx) == 1 .or. mxGetN(ysteady_mx) == 1))) then
call mexErrMsgTxt("9th argument (ysteady) should be a real vector")
if (.not. (mxIsDouble(ysteady_mx) .and. (mxGetM(ysteady_mx) == 1 .or. mxGetN(ysteady_mx) == 1)) &
.or. mxIsComplex(ysteady_mx) .or. mxIsSparse(ysteady_mx)) then
call mexErrMsgTxt("9th argument (ysteady) should be a real dense vector")
end if
if (.not. mxIsStruct(dr_mx)) then
call mexErrMsgTxt("10th argument (dr) should be a struct")
@ -130,7 +132,7 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
do i = 0, order
write (fieldname, '(a2, i1)') "g_", i
tmp = mxGetField(dr_mx, 1_mwIndex, trim(fieldname))
if (.not. (c_associated(tmp) .and. mxIsDouble(tmp))) then
if (.not. (c_associated(tmp) .and. mxIsDouble(tmp) .and. .not. mxIsComplex(tmp) .and. .not. mxIsSparse(tmp))) then
call mexErrMsgTxt(trim(fieldname)//" is not allocated in dr")
end if
m = int(mxGetM(tmp))

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2021 Dynare Team
* Copyright © 2021-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -194,8 +194,8 @@ extern "C" {
mexErrMsgTxt("The derivatives were not computed for the required order. Make sure that you used the right order option inside the `stoch_simul' command");
const mxArray *nnzderivatives_obj_mx = mxGetField(M_mx, 0, "NNZDerivatives_objective");
if (!(nnzderivatives_obj_mx && mxIsDouble(nnzderivatives_obj_mx)))
mexErrMsgTxt("M_.NNZDerivatives should be a double precision array");
if (!(nnzderivatives_obj_mx && mxIsDouble(nnzderivatives_obj_mx) && !mxIsComplex(nnzderivatives_obj_mx) && !mxIsSparse(nnzderivatives_obj_mx)))
mexErrMsgTxt("M_.NNZDerivatives should be a real dense array");
ConstVector NNZD_obj{nnzderivatives_obj_mx};
if (NNZD.length() < kOrder || NNZD_obj[kOrder-1] == -1)
mexErrMsgTxt("The derivatives were not computed for the required order. Make sure that you used the right order option inside the `stoch_simul' command");
@ -211,21 +211,24 @@ extern "C" {
std::vector<std::string> exoNames = DynareMxArrayToString(exo_names_mx);
const mxArray *dynamic_tmp_nbr_mx = mxGetField(M_mx, 0, "dynamic_tmp_nbr");
if (!(dynamic_tmp_nbr_mx && mxIsDouble(dynamic_tmp_nbr_mx) && mxGetNumberOfElements(dynamic_tmp_nbr_mx) >= static_cast<size_t>(kOrder+1)))
if (!(dynamic_tmp_nbr_mx && mxIsDouble(dynamic_tmp_nbr_mx) && !mxIsComplex(dynamic_tmp_nbr_mx)
&& !mxIsSparse(dynamic_tmp_nbr_mx) && mxGetNumberOfElements(dynamic_tmp_nbr_mx) >= static_cast<size_t>(kOrder+1)))
mexErrMsgTxt("M_.dynamic_tmp_nbr should be a double precision array with strictly more elements than the order of derivation");
int ntt = std::accumulate(mxGetPr(dynamic_tmp_nbr_mx), mxGetPr(dynamic_tmp_nbr_mx)+kOrder+1, 0);
// Extract various fields from dr
const mxArray *ys_mx = mxGetField(dr_mx, 0, "ys"); // and not in order of dr.order_var
if (!(ys_mx && mxIsDouble(ys_mx)))
mexErrMsgTxt("dr.ys should be a double precision array");
if (!(ys_mx && mxIsDouble(ys_mx) && !mxIsComplex(ys_mx) && !mxIsSparse(ys_mx)))
mexErrMsgTxt("dr.ys should be a real dense array");
Vector ySteady{ConstVector{ys_mx}};
if (!ySteady.isFinite())
mexErrMsgTxt("dr.ys contains NaN or Inf");
const mxArray *order_var_mx = mxGetField(dr_mx, 0, "order_var");
if (!(order_var_mx && mxIsDouble(order_var_mx) && mxGetNumberOfElements(order_var_mx) == static_cast<size_t>(nEndo)))
mexErrMsgTxt("dr.order_var should be a double precision array of M_.endo_nbr elements");
if (!(order_var_mx && mxIsDouble(order_var_mx) && !mxIsComplex(order_var_mx)
&& !mxIsSparse(order_var_mx)
&& mxGetNumberOfElements(order_var_mx) == static_cast<size_t>(nEndo)))
mexErrMsgTxt("dr.order_var should be a real dense array of M_.endo_nbr elements");
std::vector<int> dr_order(nEndo);
std::transform(mxGetPr(order_var_mx), mxGetPr(order_var_mx)+nEndo, dr_order.begin(),
[](double x) { return static_cast<int>(x)-1; });
@ -262,8 +265,10 @@ extern "C" {
app.walkStochSteady();
const mxArray *objective_tmp_nbr_mx = mxGetField(M_mx, 0, "objective_tmp_nbr");
if (!(objective_tmp_nbr_mx && mxIsDouble(objective_tmp_nbr_mx) && mxGetNumberOfElements(objective_tmp_nbr_mx) >= static_cast<size_t>(kOrder+1)))
mexErrMsgTxt("M_.objective_tmp_nbr should be a double precision array with strictly more elements than the order of derivation");
if (!(objective_tmp_nbr_mx && mxIsDouble(objective_tmp_nbr_mx)
&& !mxIsComplex(objective_tmp_nbr_mx) && !mxIsSparse(objective_tmp_nbr_mx)
&& mxGetNumberOfElements(objective_tmp_nbr_mx) >= static_cast<size_t>(kOrder+1)))
mexErrMsgTxt("M_.objective_tmp_nbr should be a real dense array with strictly more elements than the order of derivation");
int ntt_objective = std::accumulate(mxGetPr(objective_tmp_nbr_mx), mxGetPr(objective_tmp_nbr_mx)+kOrder+1, 0);
//Getting derivatives of the planner's objective function

View File

@ -1,7 +1,7 @@
! This MEX file computes A·(B⊗C) or A·(B⊗B) without explicitly building B⊗C or
! B⊗B, so that one can consider large matrices B and/or C.
! Copyright © 2007-2021 Dynare Team
! Copyright © 2007-2022 Dynare Team
!
! This file is part of Dynare.
!
@ -36,9 +36,9 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
call mexErrMsgTxt("A_times_B_kronecker_C takes 2 or 3 input arguments and provides 1 output argument")
end if
if (.not. mxIsDouble(prhs(1)) .or. mxIsComplex(prhs(1)) &
.or. .not. mxIsDouble(prhs(2)) .or. mxIsComplex(prhs(2))) then
call mexErrMsgTxt("A_times_B_kronecker_C: first two arguments should be real matrices")
if (.not. mxIsDouble(prhs(1)) .or. mxIsComplex(prhs(1)) .or. mxIsSparse(prhs(1)) &
.or. .not. mxIsDouble(prhs(2)) .or. mxIsComplex(prhs(2)) .or. mxIsSparse(prhs(2))) then
call mexErrMsgTxt("A_times_B_kronecker_C: first two arguments should be real dense matrices")
end if
mA = mxGetM(prhs(1))
nA = mxGetN(prhs(1))
@ -49,8 +49,8 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
if (nrhs == 3) then
! A·(B⊗C) is to be computed.
if (.not. mxIsDouble(prhs(3)) .or. mxIsComplex(prhs(3))) then
call mexErrMsgTxt("A_times_B_kronecker_C: third argument should be a real matrix")
if (.not. mxIsDouble(prhs(3)) .or. mxIsComplex(prhs(3)) .or. mxIsSparse(prhs(3))) then
call mexErrMsgTxt("A_times_B_kronecker_C: third argument should be a real dense matrix")
end if
mC = mxGetM(prhs(3))
nC = mxGetN(prhs(3))

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2007-2021 Dynare Team
* Copyright © 2007-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -141,8 +141,12 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
return; // Needed to shut up some GCC warnings
}
if (!mxIsSparse(prhs[0]))
mexErrMsgTxt("sparse_hessian_times_B_kronecker_C: First input must be a sparse (dynare) hessian matrix.");
if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) || !mxIsSparse(prhs[0]))
mexErrMsgTxt("sparse_hessian_times_B_kronecker_C: First input must be a real sparse matrix.");
if (!mxIsDouble(prhs[1]) || mxIsComplex(prhs[1]) || mxIsSparse(prhs[1]))
mexErrMsgTxt("sparse_hessian_times_B_kronecker_C: Second input must be a real dense matrix.");
if (nrhs == 4 && (!mxIsDouble(prhs[2]) || mxIsComplex(prhs[2]) || mxIsSparse(prhs[2])))
mexErrMsgTxt("sparse_hessian_times_B_kronecker_C: Third input must be a real dense matrix.");
// Get & Check dimensions (columns and rows):
size_t mA = mxGetM(prhs[0]);
@ -166,12 +170,21 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
int numthreads;
const double *B = mxGetPr(prhs[1]);
const double *C;
numthreads = static_cast<int>(mxGetScalar(prhs[2]));
const mxArray *numthreads_mx;
if (nrhs == 4)
{
C = mxGetPr(prhs[2]);
numthreads = static_cast<int>(mxGetScalar(prhs[3]));
numthreads_mx = prhs[3];
}
else
numthreads_mx = prhs[2];
if (!(mxIsScalar(numthreads_mx) && mxIsNumeric(numthreads_mx)))
mexErrMsgTxt("sparse_hessian_times_B_kronecker_C: Last input must be a numeric scalar.");
numthreads = static_cast<int>(mxGetScalar(numthreads_mx));
if (numthreads <= 0)
mexErrMsgTxt("sparse_hessian_times_B_kronecker_C: Last input must be a positive integer.");
// Sparse (dynare) hessian matrix.
const mwIndex *isparseA = mxGetIr(prhs[0]);
const mwIndex *jsparseA = mxGetJc(prhs[0]);

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2010-2021 Dynare Team
* Copyright © 2010-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -25,6 +25,7 @@
#include <vector>
#include <algorithm>
#include <tuple>
#include <string>
#include <dynmex.h>
#include <dynblas.h>
@ -224,6 +225,15 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
if (nlhs > 2)
mexErrMsgTxt("Too many output arguments.");
auto check_input_real_dense_array = [=](int i)
{
if (!mxIsDouble(prhs[i]) || mxIsComplex(prhs[i]) || mxIsSparse(prhs[i]))
mexErrMsgTxt(("Input argument " + std::to_string(i+1) + " should be a real dense array").c_str());
};
for (int i = 0; i < 8; i++)
check_input_real_dense_array(i);
// Get dimensions.
size_t n = mxGetM(prhs[0]); // Number of states.
size_t s = mxGetN(prhs[0]); // Number of particles.
@ -243,10 +253,15 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|| n*q != mxGetN(prhs[7])) // Number of rows for ghxu
mexErrMsgTxt("Input dimension mismatch!.");
if (nrhs > 9)
if (n != mxGetM(prhs[8]) // Number of rows for yhat_
|| s != mxGetN(prhs[8]) // Number of columns for yhat_
|| m != mxGetM(prhs[9])) // Number of rows for ss
mexErrMsgTxt("Input dimension mismatch!.");
{
for (int i = 8; i < 10; i++)
check_input_real_dense_array(i);
if (n != mxGetM(prhs[8]) // Number of rows for yhat_
|| s != mxGetN(prhs[8]) // Number of columns for yhat_
|| m != mxGetM(prhs[9])) // Number of rows for ss
mexErrMsgTxt("Input dimension mismatch!.");
}
// Get Input arrays.
const double *yhat = mxGetPr(prhs[0]);
@ -263,7 +278,14 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
yhat_ = mxGetPr(prhs[8]);
ss = mxGetPr(prhs[9]);
}
int numthreads = static_cast<int>(mxGetScalar(prhs[nrhs == 9 ? 8 : 10]));
const mxArray *numthreads_mx = prhs[nrhs == 9 ? 8 : 10];
if (!(mxIsScalar(numthreads_mx) && mxIsNumeric(numthreads_mx)))
mexErrMsgTxt("Last argument should be a numeric scalar");
int numthreads = static_cast<int>(mxGetScalar(numthreads_mx));
if (numthreads <= 0)
mexErrMsgTxt("Last argument should be a positive integer");
#if defined(USE_BLAS_AT_FIRST_ORDER) && defined(MATLAB_MEX_FILE)
if (numthreads != 1)
mexErrMsgTxt("Parallelization is not possible when compiled with USE_BLAS_AT_FIRST_ORDER.");

View File

@ -58,11 +58,13 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
if (nrhs /= 6 .or. nlhs /= 1) then
call mexErrMsgTxt("Must have exactly 5 inputs and 1 output")
end if
if (.not. (mxIsDouble(yhat_mx) .and. mxGetM(yhat_mx) >= 1 .and. mxGetN(yhat_mx) >= 1)) then
call mexErrMsgTxt("1st argument (yhat) should be a real vector")
if (.not. (mxIsDouble(yhat_mx) .and. mxGetM(yhat_mx) >= 1 .and. mxGetN(yhat_mx) >= 1) &
.or. mxIsComplex(yhat_mx) .or. mxIsSparse(yhat_mx)) then
call mexErrMsgTxt("1st argument (yhat) should be a real dense vector")
end if
if (.not. (mxIsDouble(epsilon_mx) .and. mxGetM(epsilon_mx) >= 1 .or. mxGetN(epsilon_mx) == 1)) then
call mexErrMsgTxt("2nd argument (epsilon) should be a real vector")
if (.not. (mxIsDouble(epsilon_mx) .and. mxGetM(epsilon_mx) >= 1 .or. mxGetN(epsilon_mx) == 1) &
.or. mxIsComplex(epsilon_mx) .or. mxIsSparse(epsilon_mx)) then
call mexErrMsgTxt("2nd argument (epsilon) should be a real dense vector")
end if
if (.not. mxIsStruct(dr_mx)) then
call mexErrMsgTxt("3rd argument (dr) should be a struct")
@ -88,15 +90,17 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
nvar = nys + exo_nbr
associate (order_var_mx => mxGetField(dr_mx, 1_mwIndex, "order_var"))
if (.not. (mxIsDouble(order_var_mx) .and. int(mxGetNumberOfElements(order_var_mx)) == endo_nbr)) then
call mexErrMsgTxt("Field dr.order_var should be a double precision vector with endo_nbr elements")
if (.not. (mxIsDouble(order_var_mx) .and. int(mxGetNumberOfElements(order_var_mx)) == endo_nbr) &
.or. mxIsComplex(order_var_mx) .or. mxIsSparse(order_var_mx)) then
call mexErrMsgTxt("Field dr.order_var should be a real dense vector with endo_nbr elements")
end if
order_var => mxGetPr(order_var_mx)
end associate
associate (ys_mx => mxGetField(dr_mx, 1_mwIndex, "ys"))
if (.not. (mxIsDouble(ys_mx) .and. int(mxGetNumberOfElements(ys_mx)) == endo_nbr)) then
call mexErrMsgTxt("Field dr.ys should be a double precision vector with endo_nbr elements")
if (.not. (mxIsDouble(ys_mx) .and. int(mxGetNumberOfElements(ys_mx)) == endo_nbr) &
.or. mxIsComplex(ys_mx) .or. mxIsSparse(ys_mx)) then
call mexErrMsgTxt("Field dr.ys should be a real dense vector with endo_nbr elements")
end if
ys => mxGetPr(ys_mx)
! Construct the reordered steady state
@ -107,8 +111,8 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
end associate
associate (restrict_var_list_mx => mxGetField(dr_mx, 1_mwIndex, "restrict_var_list"))
if (.not. (mxIsDouble(restrict_var_list_mx))) then
call mexErrMsgTxt("Field dr.restrict_var_list should be a double precision vector")
if (.not. mxIsDouble(restrict_var_list_mx) .or. mxIsComplex(restrict_var_list_mx) .or. mxIsSparse(restrict_var_list_mx)) then
call mexErrMsgTxt("Field dr.restrict_var_list should be a real dense vector")
end if
nrestricted = size(mxGetPr(restrict_var_list_mx))
restrict_var_list => mxGetPr(restrict_var_list_mx)

View File

@ -28,7 +28,7 @@
! Fortran compiler better optimize the code (in some cases, this will avoid
! array copies)
! Copyright © 2019-2021 Dynare Team
! Copyright © 2019-2022 Dynare Team
!
! This file is part of Dynare.
!
@ -177,6 +177,11 @@ module matlab_mat
integer(mxComplexity), intent(in), value :: ComplexFlag
end function mxCreateSparse
logical(c_bool) function mxIsSparse(pm) bind(c, name="mxIsSparse"//API_VER)
use iso_c_binding
type(c_ptr), intent(in), value :: pm
end function mxIsSparse
type(c_ptr) function mxGetIr(pm) bind(c, name="mxGetIr"//API_VER2)
use iso_c_binding
type(c_ptr), intent(in), value :: pm

View File

@ -18,7 +18,7 @@
! eigval [complex] (n×1) vector of generalized eigenvalues
! info [integer] scalar, error code of dgges (or 30 if eigenvalue close to 0÷0)
! Copyright © 2006-2021 Dynare Team
! Copyright © 2006-2022 Dynare Team
!
! This file is part of Dynare.
!
@ -83,10 +83,10 @@ subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
end if
n = mxGetM(prhs(1))
if (.not. mxIsDouble(prhs(1)) .or. mxIsComplex(prhs(1)) &
.or. .not. mxIsDouble(prhs(2)) .or. mxIsComplex(prhs(2)) &
if (.not. mxIsDouble(prhs(1)) .or. mxIsComplex(prhs(1)) .or. mxIsSparse(prhs(1)) &
.or. .not. mxIsDouble(prhs(2)) .or. mxIsComplex(prhs(2)) .or. mxIsSparse(prhs(2)) &
.or. mxGetN(prhs(1)) /= n .or. mxGetM(prhs(2)) /= n .or. mxGetN(prhs(2)) /= n) then
call mexErrMsgTxt("MJDGGES: first two arguments should be real matrices of the same dimension")
call mexErrMsgTxt("MJDGGES: first two arguments should be real dense matrices of the same dimension")
end if
! Set criterium for stable eigenvalues

View File

@ -160,6 +160,12 @@ DynamicModelMatlabCaller::eval(int it, double *resid)
return; // Avoid manipulating null pointers in plhs, see #1832
}
if (!mxIsDouble(plhs[0]) || mxIsSparse(plhs[0]))
{
error_msg = "Residuals should be a dense array of double floats";
return;
}
if (mxIsComplex(plhs[0]))
plhs[0] = cmplxToReal(plhs[0]);
@ -186,6 +192,12 @@ DynamicModelMatlabCaller::eval(int it, double *resid)
jacobian_mx = nullptr;
}
if (!mxIsDouble(plhs[0]) || mxIsSparse(plhs[0]))
{
error_msg = "Jacobian should be a dense array of double floats";
return;
}
if (mxIsComplex(plhs[0]))
jacobian_mx = cmplxToReal(plhs[0]);
else
@ -196,6 +208,8 @@ DynamicModelMatlabCaller::eval(int it, double *resid)
}
}
/* NB: This is a duplicate of DynamicModelMFile::cmplxToReal() in
k_order_perturbation MEX */
mxArray *
DynamicModelMatlabCaller::cmplxToReal(mxArray *cmplx_mx)
{

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2019 Dynare Team
* Copyright © 2019-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -87,7 +87,7 @@ class DynamicModelMatlabCaller : public DynamicModelCaller
private:
std::string basename;
mxArray *T_mx, *y_mx, *it_mx, *T_flag_mx, *jacobian_mx, *x_mx, *params_mx, *steady_state_mx;
/* Given a complex matrix, returns a real matrix of same size.
/* Given a complex dense matrix (of double floats), returns a real dense matrix of same size.
Real elements of the original matrix are copied as-is to the new one.
Complex elements are replaced by NaNs.
Destroys the original matrix. */

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2019-2020 Dynare Team
* Copyright © 2019-2022 Dynare Team
*
* This file is part of Dynare.
*
@ -65,14 +65,16 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mwIndex maximum_endo_lag = static_cast<mwIndex>(mxGetScalar(maximum_endo_lag_mx));
const mxArray *dynamic_tmp_nbr_mx = mxGetField(M_mx, 0, "dynamic_tmp_nbr");
if (!(dynamic_tmp_nbr_mx && mxIsDouble(dynamic_tmp_nbr_mx) && mxGetNumberOfElements(dynamic_tmp_nbr_mx) >= 2))
mexErrMsgTxt("M_.dynamic_tmp_nbr should be a double array of at least 2 elements");
if (!(dynamic_tmp_nbr_mx && mxIsDouble(dynamic_tmp_nbr_mx) && mxGetNumberOfElements(dynamic_tmp_nbr_mx) >= 2)
|| mxIsComplex(dynamic_tmp_nbr_mx) || mxIsSparse(dynamic_tmp_nbr_mx))
mexErrMsgTxt("M_.dynamic_tmp_nbr should be a real dense array of at least 2 elements");
size_t ntt = mxGetPr(dynamic_tmp_nbr_mx)[0] + mxGetPr(dynamic_tmp_nbr_mx)[1];
const mxArray *lead_lag_incidence_mx = mxGetField(M_mx, 0, "lead_lag_incidence");
if (!(lead_lag_incidence_mx && mxIsDouble(lead_lag_incidence_mx) && mxGetM(lead_lag_incidence_mx) == static_cast<size_t>(2+maximum_endo_lag)
&& mxGetN(lead_lag_incidence_mx) == static_cast<size_t>(ny)))
mexErrMsgTxt("M_.lead_lag_incidence should be a double precision matrix with 2+M_.maximum_endo_lag rows and M_.endo_nbr columns");
&& mxGetN(lead_lag_incidence_mx) == static_cast<size_t>(ny))
|| mxIsComplex(lead_lag_incidence_mx) || mxIsSparse(lead_lag_incidence_mx))
mexErrMsgTxt("M_.lead_lag_incidence should be a real dense matrix with 2+M_.maximum_endo_lag rows and M_.endo_nbr columns");
const double *lead_lag_incidence = mxGetPr(lead_lag_incidence_mx);
const mxArray *has_external_function_mx = mxGetField(M_mx, 0, "has_external_function");

View File

@ -1,7 +1,7 @@
/*
** Computes Quasi Monte-Carlo sequence.
**
** Copyright © 2010-2020 Dynare Team
** Copyright © 2010-2022 Dynare Team
**
** This file is part of Dynare (can be used outside Dynare).
**
@ -60,10 +60,13 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
/*
** Test the first input argument and assign it to dimension.
*/
if (!mxIsNumeric(prhs[0]))
mexErrMsgTxt("qmc_sequence:: First input (dimension) has to be a positive integer!");
if (!(mxIsScalar(prhs[0]) && mxIsNumeric(prhs[0])))
mexErrMsgTxt("qmc_sequence:: First input (dimension) has to be a numeric scalar!");
int dimension = static_cast<int>(mxGetScalar(prhs[0]));
if (dimension <= 0)
mexErrMsgTxt("qmc_sequence:: First input (dimension) has to be a positive integer!");
/*
** Test the second input argument and assign it to seed.
*/
@ -75,7 +78,7 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
** Test the third input argument and assign it to type (kind of QMC sequence).
*/
int error_flag_3 = 0;
if (!mxIsNumeric(prhs[2]))
if (!(mxIsScalar(prhs[2]) && mxIsNumeric(prhs[2])))
error_flag_3 = 1;
int type = static_cast<int>(mxGetScalar(prhs[2]));
@ -97,30 +100,37 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
/*
** Test the optional fourth input argument and assign it to sequence_size.
*/
if (nrhs > 3 && !mxIsNumeric(prhs[3]))
mexErrMsgTxt("qmc_sequence:: Fourth input (qmc sequence size) has to be a positive integer!");
if (nrhs > 3 && !(mxIsScalar(prhs[3]) && mxIsNumeric(prhs[3])))
mexErrMsgTxt("qmc_sequence:: Fourth input (qmc sequence size) has to be a numeric scalar!");
int sequence_size;
if (nrhs > 3)
sequence_size = static_cast<int>(mxGetScalar(prhs[3]));
{
sequence_size = static_cast<int>(mxGetScalar(prhs[3]));
if (sequence_size <= 0)
mexErrMsgTxt("qmc_sequence:: Fourth input (qmc sequence size) has to be a positive integer!");
}
else
sequence_size = 1;
/*
** Test the optional fifth input argument and assign it to lower_and_upper_bounds.
*/
if (nrhs > 4 && type == 0 && mxGetN(prhs[4]) != 2) // Sequence of uniformly distributed numbers in an hypercube
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be an array with two columns!");
if (nrhs > 4 && type == 0
&& !(mxIsDouble(prhs[4]) && !mxIsComplex(prhs[4]) && !mxIsSparse(prhs[4])
&& mxGetN(prhs[4]) == 2
&& static_cast<int>(mxGetM(prhs[4])) == dimension)) // Sequence of uniformly distributed numbers in an hypercube
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be a real dense array with two columns and number of lines equal to dimension (first input argument)!");
if (nrhs > 4 && type == 0 && static_cast<int>(mxGetM(prhs[4])) != dimension)
mexErrMsgTxt("qmc_sequence:: The fourth input argument must be an array with a number of lines equal to dimension (first input argument)!");
if (nrhs > 4 && type == 1
&& !(mxIsDouble(prhs[4]) && !mxIsComplex(prhs[4]) && !mxIsSparse(prhs[4])
&& static_cast<int>(mxGetN(prhs[4])) == dimension
&& static_cast<int>(mxGetM(prhs[4])) == dimension)) // Sequence of normally distributed numbers
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be a real dense square matrix (whose dimension is given by the first input argument)!");
if (nrhs > 4 && type == 1 && !(static_cast<int>(mxGetN(prhs[4])) == dimension
&& static_cast<int>(mxGetM(prhs[4])) == dimension)) // Sequence of normally distributed numbers
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be a squared matrix (whose dimension is given by the first input argument)!");
if (nrhs > 4 && type == 2 && !(mxGetN(prhs[4]) == 1 && mxGetM(prhs[4]) == 1)) // Sequence of uniformly distributed numbers on a hypershere
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be a positive scalar!");
if (nrhs > 4 && type == 2
&& !(mxIsScalar(prhs[4]) && mxIsNumeric(prhs[4]))) // Sequence of uniformly distributed numbers on a hypershere
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be a numeric scalar!");
const double *lower_bounds = nullptr, *upper_bounds = nullptr;
int unit_hypercube_flag = 1;
@ -141,7 +151,9 @@ mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
int unit_radius = 1;
if (type == 2 && nrhs > 4)
{
radius = *mxGetPr(prhs[4]);
radius = mxGetScalar(prhs[4]);
if (radius <= 0)
mexErrMsgTxt("qmc_sequence:: The fifth input argument must be a positive real number!");
unit_radius = 0;
}
/*