Skip to content

Instantly share code, notes, and snippets.

@tavert
Last active December 25, 2015 01:59
Show Gist options
  • Save tavert/6898980 to your computer and use it in GitHub Desktop.
Save tavert/6898980 to your computer and use it in GitHub Desktop.
Prototype nonlinear Matlab interface to generate OSiL-format optimization problem instances. Currently only handles scalar variables and can only determine linear coefficients for simple constraints, but appears to work at least for small problems. Based on simple operator overloading and fairly thin wrappers around the OSiL XML content. Problem…
clear
instance = OSinstance;
instance.instanceHeader.name = 'Bonmin Example';
instance.instanceHeader.source = 'Bonmin example folder';
instance.instanceHeader.description = sprintf(['Objective value: -1.70711\n' ...
'\t\t\tSolution:\n' ...
'\t\t\tx[0] = 0, x[1] = 0.853553, x[2] = 0.853553, x[3] = 1']);
% var = instance.createVariable(name, type, lb, ub, mult)
x0 = instance.createVariable('x0', 'B', 0, 1);
x1 = instance.createVariable('x1', 'C', 0);
x2 = instance.createVariable('x2', 'C', 0);
x3 = instance.createVariable('x3', 'I', 0, 5);
% instance.setObjective(expression, name, maxOrMin)
instance.setObjective(x0 - x1 - x2, 'minCost', 'min');
% instance.createConstraint(expression, name, constant, lb, ub, mult)
instance.createConstraint((x1 - 0.5)^2 + (x2 - 0.5)^2, [], [], [], 0.25);
instance.createConstraint(x0 - x1, [], [], [], 0);
instance.createConstraint(x1 + x2 + x3, [], [], [], 2);
xmlwrite(instance.document)
xmlwrite('bonminEx1_nonlinear_out.osil', instance.document);
% Matlab class for Optimization Services instance
classdef OSinstance < handle
properties
document
instanceHeader
instanceData
end
methods
function instance = OSinstance
% default constructor
instance.document = ...
com.mathworks.xml.XMLUtils.createDocument('osil');
docRootNode = instance.document.getDocumentElement;
docRootNode.setAttribute('xmlns', ...
'os.optimizationservices.org');
docRootNode.setAttribute('xmlns:xsi', ...
'http://www.w3.org/2001/XMLSchema-instance');
docRootNode.setAttribute('xsi:schemaLocation', ...
['os.optimizationservices.org ' ...
'http://www.optimizationservices.org/schemas/2.0/OSiL.xsd']);
instance.instanceHeader.element = ...
instance.document.createElement('instanceHeader');
instance.instanceData.element = ...
instance.document.createElement('instanceData');
docRootNode.appendChild(instance.instanceHeader.element);
docRootNode.appendChild(instance.instanceData.element);
variables = instance.document.createElement('variables');
variables.setAttribute('numberOfVariables', '0');
instance.instanceData.variables.element = variables;
instance.instanceData.variables.numberOfVariables = 0;
instance.instanceData.element.appendChild(variables);
% only implementing single-objective problems for now
objectives = instance.document.createElement('objectives');
obj = instance.document.createElement('obj');
obj.setAttribute('maxOrMin', 'min');
obj.setAttribute('numberOfObjCoef', '0');
objectives.appendChild(obj);
instance.instanceData.objectives.element = objectives;
instance.instanceData.objectives.obj.element = obj;
instance.instanceData.element.appendChild(objectives);
constraints = instance.document.createElement('constraints');
constraints.setAttribute('numberOfConstraints', '0');
instance.instanceData.constraints.element = constraints;
instance.instanceData.constraints.numberOfConstraints = 0;
instance.instanceData.element.appendChild(constraints);
linearConstraintCoefficients = ...
instance.document.createElement('linearConstraintCoefficients');
linearConstraintCoefficients.setAttribute('numberOfValues', '0');
start = instance.document.createElement('start');
el = instance.document.createElement('el');
txt = instance.document.createTextNode('0');
el.appendChild(txt);
start.appendChild(el);
colIdx = instance.document.createElement('colIdx');
value = instance.document.createElement('value');
linearConstraintCoefficients.appendChild(start);
linearConstraintCoefficients.appendChild(colIdx);
linearConstraintCoefficients.appendChild(value);
instance.instanceData.linearConstraintCoefficients = ...
struct('element', linearConstraintCoefficients, ...
'start', start, 'colIdx', colIdx, 'value', value, ...
'numberOfValues', 0);
nonlinearExpressions = instance.document.createElement( ...
'nonlinearExpressions');
nonlinearExpressions.setAttribute( ...
'numberOfNonlinearExpressions', '1');
objectiveNL = instance.document.createElement('nl');
objectiveNL.setAttribute('idx', '-1');
dummyobjective = OSnonlinear(objectiveNL, 0);
objectiveNL.appendChild(dummyobjective.element);
nonlinearExpressions.appendChild(objectiveNL);
instance.instanceData.nonlinearExpressions = ...
struct('element', nonlinearExpressions, 'objectiveNL', ...
objectiveNL, 'numberOfNonlinearExpressions', 1);
instance.instanceData.element.appendChild(nonlinearExpressions);
end
function set.instanceHeader(instance, value)
% property set function for instanceHeader.name,
% instanceHeader.source, and instanceHeader.description
if ~isstruct(value)
error('instanceHeader must be a structure')
end
fnames = fieldnames(value);
for i=1:length(fnames)
switch fnames{i}
case 'element'
instance.instanceHeader.element = value.element;
case {'name', 'source', 'description'}
instance.instanceHeader.(fnames{i}) = ...
value.(fnames{i});
if isfield(instance.instanceHeader, ...
[fnames{i} 'Text'])
instance.instanceHeader.([fnames{i} ...
'Text']).setTextContent(value.(fnames{i}));
else
docu = instance.instanceHeader.element.getOwnerDocument;
newelem = docu.createElement(fnames{i});
instance.instanceHeader.([fnames{i} 'Text']) = ...
docu.createTextNode(value.(fnames{i}));
newelem.appendChild( ...
instance.instanceHeader.([fnames{i} 'Text']));
instance.instanceHeader.element.appendChild(newelem);
end
case {'nameText', 'sourceText', 'descriptionText'}
% ignore these
otherwise
error('invalid field for instanceHeader')
end
end
end
function variable = createVariable(instance, name, type, lb, ub, mult)
variables = instance.instanceData.variables;
numvars_prev = variables.numberOfVariables;
% first new element goes in instanceData.variables
elem1 = instance.document.createElement('var');
if nargin > 1 && ~isempty(name)
elem1.setAttribute('name', name);
end
if nargin > 2 && ~isempty(type)
elem1.setAttribute('type', type);
end
if nargin > 3 && ~isempty(lb)
elem1.setAttribute('lb', sprintf('%.17g', lb));
else
% either set lb to -INF by default, or make very clear in docu?
%warning('OSinstance:lb0','note that lb = 0 by default in OSiL')
end
if nargin > 4 && ~isempty(ub)
elem1.setAttribute('ub', sprintf('%.17g', ub));
end
if nargin > 5 && ~isempty(mult)
if mult ~= 1
error('mult ~= 1 not currently supported')
end
elem1.setAttribute('mult', sprintf('%d', mult));
end
variables.element.appendChild(elem1);
instance.instanceData.variables.numberOfVariables = ...
numvars_prev + 1;
variables.element.setAttribute('numberOfVariables', ...
sprintf('%d', numvars_prev + 1));
% second new element goes in output nonlinear expression
elem2 = instance.document.createElement('variable');
elem2.setAttribute('idx', sprintf('%d', numvars_prev));
elem2.setAttribute('coef', '1.0');
variable = OSnonlinear(elem2);
% ideally want a way of setting variable properties after
% creation too, probably through the OSnonlinear object
end
function setObjective(instance, expression, name, maxOrMin)
% numberOfObjCoef? constant? weight? mult?
% clear attributes or set to default if not specified?
obj = instance.instanceData.objectives.obj.element;
if nargin > 2 && ~isempty(name)
obj.setAttribute('name', name);
end
if nargin > 3 && ~isempty(maxOrMin)
obj.setAttribute('maxOrMin', maxOrMin);
end
objectiveNL = instance.instanceData.nonlinearExpressions.objectiveNL;
objectiveNL.replaceChild(expression.element, ...
objectiveNL.getFirstChild);
end
function createConstraint(instance, expression, ...
name, constant, lb, ub, mult)
constraints = instance.instanceData.constraints;
numconstr_prev = constraints.numberOfConstraints;
linearConstraintCoefficients = ...
instance.instanceData.linearConstraintCoefficients;
numlinvals_prev = linearConstraintCoefficients.numberOfValues;
numlinvals_new = numlinvals_prev;
% check if new constraint is linear
[idx, val] = linearCoefficients(expression);
if ~isempty(idx)
offset = sum(val(idx == -1));
% use sparse to combine coefficients for duplicate indices
coefvec = sparse(idx(idx > 0), 1, val(idx > 0));
numlinvals_new = numlinvals_new + nnz(coefvec);
instance.instanceData.linearConstraintCoefficients.numberOfValues = ...
numlinvals_new;
linearConstraintCoefficients.element.setAttribute( ...
'numberOfValues', sprintf('%d', numlinvals_new));
[idx, ~, val] = find(coefvec);
for i=1:nnz(coefvec)
% add new entry to linearConstraintCoefficients.colIdx
el = instance.document.createElement('el');
txt = instance.document.createTextNode( ...
sprintf('%d', idx(i) - 1)); % zero-based colIdx
el.appendChild(txt);
linearConstraintCoefficients.colIdx.appendChild(el);
% add new entry to linearConstraintCoefficients.value
el = instance.document.createElement('el');
txt = instance.document.createTextNode( ...
sprintf('%.17g', val(i)));
el.appendChild(txt);
linearConstraintCoefficients.value.appendChild(el);
end
if numlinvals_prev == 0
% add linearConstraintCoefficients section to
% instanceData if it was previously empty
instance.instanceData.element.insertBefore( ...
linearConstraintCoefficients.element, ...
instance.instanceData.nonlinearExpressions.element);
end
% adjust constant to account for offset
if nargin > 3 && ~isempty(constant)
constant = constant + offset;
elseif offset ~= 0
constant = offset;
end
else
% constraint is nonlinear, so add new element
% in instanceData.nonlinearExpressions
conNL = instance.document.createElement('nl');
conNL.setAttribute('idx', sprintf('%d', numconstr_prev));
conNL.appendChild(expression.element.cloneNode(true));
nonlinearExpressions = instance.instanceData.nonlinearExpressions;
numNL_prev = nonlinearExpressions.numberOfNonlinearExpressions;
nonlinearExpressions.element.appendChild(conNL);
instance.instanceData.nonlinearExpressions.numberOfNonlinearExpressions = ...
numNL_prev + 1;
nonlinearExpressions.element.setAttribute( ...
'numberOfNonlinearExpressions', ...
sprintf('%d', numNL_prev + 1));
end
% add new element to instanceData.constraints
con = instance.document.createElement('con');
if nargin > 2 && ~isempty(name)
con.setAttribute('name', name);
end
if exist('constant', 'var') && ~isempty(constant)
con.setAttribute('constant', sprintf('%.17g', constant));
end
if nargin > 4 && ~isempty(lb)
con.setAttribute('lb', sprintf('%.17g', lb));
end
if nargin > 5 && ~isempty(ub)
con.setAttribute('ub', sprintf('%.17g', ub));
end
if nargin > 6 && ~isempty(mult)
if mult ~= 1
error('mult ~= 1 not currently supported')
end
con.setAttribute('mult', sprintf('%d', mult));
end
constraints.element.appendChild(con);
instance.instanceData.constraints.numberOfConstraints = ...
numconstr_prev + 1;
constraints.element.setAttribute('numberOfConstraints', ...
sprintf('%d', numconstr_prev + 1));
% add new entry to linearConstraintCoefficients.start
el = instance.document.createElement('el');
txt = instance.document.createTextNode( ...
sprintf('%d', numlinvals_new));
el.appendChild(txt);
linearConstraintCoefficients.start.appendChild(el);
end
function variable = substitutionVariable(instance, expression, varargin)
% create a new variable to replace a nonlinear expression
% and add a corresponding equality constraint
variable = instance.createVariable(varargin{:});
instance.createConstraint(-variable + expression, [], [], 0, 0);
end
function matrix = linearConstraintMatrix(instance)
% assemble the linear constraint matrix for Matlab use
lcc = instance.instanceData.linearConstraintCoefficients;
colIdx = zeros(lcc.numberOfValues, 1); % preallocate
value = zeros(lcc.numberOfValues, 1); % preallocate
for i=1:lcc.numberOfValues
colIdx(i) = str2double(lcc.colIdx.item(i-1).getTextContent);
value(i) = str2double(lcc.value.item(i-1).getTextContent);
end
start = zeros(lcc.start.getLength, 1); % preallocate
rowIdx = zeros(lcc.numberOfValues, 1); % preallocate
start(1) = str2double(lcc.start.item(0).getTextContent);
for i=1:length(start)-1
start(i+1) = str2double(lcc.start.item(i).getTextContent);
rowIdx(start(i)+1 : start(i+1)) = i;
end
matrix = sparse(rowIdx, colIdx + 1, value, length(start)-1, ...
instance.instanceData.variables.numberOfVariables);
end
end
end
% Matlab class for Optimization Services nonlinear expression
classdef OSnonlinear < handle
properties
element % xml element
fcn % Matlab function representation
end
methods
function nonlinear = OSnonlinear(element, number)
if nargin == 1
nonlinear.element = element;
if element.getNodeName.equals('variable')
idx = str2double(element.getAttribute('idx'));
coef = str2double(element.getAttribute('coef'));
nonlinear.fcn = @(x) coef*x(idx+1); % 1-based indexing
end
elseif nargin > 1
% create nonlinear expression from a number
% in parent document of first input
if length(number) > 1
error('only scalars currently supported')
end
if isa(element, 'OSinstance')
document = element.document;
else
document = element.getOwnerDocument;
end
nonlinear.element = document.createElement('number');
nonlinear.element.setAttribute('value', ...
sprintf('%.17g', number));
nonlinear.fcn = @(x) number;
end
end
function [idx, val] = linearCoefficients(in)
% determine whether an OSnonlinear object is linear
% if nonlinear, return empty
% if linear, return vector of (1-based) indices
% and vector of coefficient values
% constant terms are assigned idx = -1
% currently only handles sum, minus, variable, or number elements
idx = [];
val = [];
if in.element.getNodeName.equals('sum')
imax = in.element.getLength;
elem = in.element.getFirstChild;
idx = zeros(imax, 1); % preallocate
val = zeros(imax, 1); % preallocate
elseif in.element.getNodeName.equals('minus')
% handle subtraction recursively on each child
[idx, val] = linearCoefficients( ...
OSnonlinear(in.element.getFirstChild));
if isempty(idx) || isempty(val)
% first child is nonlinear
return
end
[idx2, val2] = linearCoefficients( ...
OSnonlinear(in.element.getLastChild));
if isempty(idx2) || isempty(val2)
% second child is nonlinear
idx = idx2;
val = val2;
else
% both children are linear
idx = [idx; idx2];
val = [val; -val2];
end
return
else
imax = 1;
elem = in.element;
end
for i=1:imax
if elem.getNodeName.equals('variable')
idx(i) = str2double(elem.getAttribute('idx')) + 1;
val(i) = str2double(elem.getAttribute('coef'));
elseif elem.getNodeName.equals('number')
idx(i) = -1;
val(i) = str2double(elem.getAttribute('value'));
else
idx = [];
val = [];
return
end
elem = elem.getNextSibling;
end
end
% should check for non-scalar inputs, add vector functions like
% norm, dot, sum, prod, concatenation?
function out = plus(in1, in2)
if isnumeric(in1)
if isequal(in1, 0)
% special case for 0
out = in2;
return
end
in1 = OSnonlinear(in2.element, in1);
elem1 = in1.element;
elem2 = in2.element.cloneNode(true);
elseif isnumeric(in2)
if isequal(in2, 0)
% special case for 0
out = in1;
return
end
in2 = OSnonlinear(in1.element, in2);
elem2 = in2.element;
elem1 = in1.element.cloneNode(true);
else
elem1 = in1.element.cloneNode(true);
elem2 = in2.element.cloneNode(true);
end
document = elem1.getOwnerDocument;
if ~isequal(document, elem2.getOwnerDocument)
error('inputs must be expressions from same OSinstance')
end
if elem1.getNodeName.equals('sum') && ...
elem2.getNodeName.equals('sum')
outelem = elem1;
for i=1:elem2.getLength
outelem.appendChild(elem2.getFirstChild);
end
elseif elem1.getNodeName.equals('sum')
outelem = elem1;
outelem.appendChild(elem2);
elseif elem2.getNodeName.equals('sum')
outelem = elem2;
outelem.insertBefore(elem1, outelem.getFirstChild);
else
outelem = document.createElement('sum');
outelem.appendChild(elem1);
outelem.appendChild(elem2);
end
out = OSnonlinear(outelem);
out.fcn = @(x) in1.fcn(x) + in2.fcn(x);
end
function out = minus(in1, in2)
if isnumeric(in2) || in2.element.getNodeName.equals('variable')
% subtract constant by adding opposite value,
% subtract variable by swapping sign of coef (see uminus)
out = in1 + (-in2);
return
elseif isnumeric(in1)
if isequal(in1, 0)
% special case for 0
out = -in2;
return
end
in1 = OSnonlinear(in2.element, in1);
elem1 = in1.element;
elem2 = in2.element.cloneNode(true);
else
elem1 = in1.element.cloneNode(true);
elem2 = in2.element.cloneNode(true);
end
document = elem1.getOwnerDocument;
if ~isequal(document, elem2.getOwnerDocument)
error('inputs must be expressions from same OSinstance')
end
outelem = document.createElement('minus');
outelem.appendChild(elem1);
outelem.appendChild(elem2);
out = OSnonlinear(outelem);
out.fcn = @(x) in1.fcn(x) - in2.fcn(x);
end
function out = mtimes(in1, in2)
if isnumeric(in1)
elem2 = in2.element.cloneNode(true);
if elem2.getNodeName.equals('variable')
% constant times variable, fold into coef
outelem = elem2;
coef = str2double(outelem.getAttribute('coef'));
outelem.setAttribute('coef', sprintf('%.17g', in1*coef));
out = OSnonlinear(outelem);
return
end
in1 = OSnonlinear(in2.element, in1);
elem1 = in1.element;
elseif isnumeric(in2)
elem1 = in1.element.cloneNode(true);
if elem1.getNodeName.equals('variable')
% variable times constant, fold into coef
outelem = elem1;
coef = str2double(outelem.getAttribute('coef'));
outelem.setAttribute('coef', sprintf('%.17g', coef*in2));
out = OSnonlinear(outelem);
return
end
in2 = OSnonlinear(in1.element, in2);
elem2 = in2.element;
else
elem1 = in1.element.cloneNode(true);
elem2 = in2.element.cloneNode(true);
end
document = elem1.getOwnerDocument;
if ~isequal(document, elem2.getOwnerDocument)
error('inputs must be expressions from same OSinstance')
end
if elem1.getNodeName.equals('product') && ...
elem2.getNodeName.equals('product')
outelem = elem1;
for i=1:elem2.getLength
outelem.appendChild(elem2.getFirstChild);
end
elseif elem1.getNodeName.equals('product')
outelem = elem1;
outelem.appendChild(elem2);
elseif elem2.getNodeName.equals('product')
outelem = elem2;
outelem.insertBefore(elem1, outelem.getFirstChild);
else
outelem = document.createElement('product');
outelem.appendChild(elem1);
outelem.appendChild(elem2);
end
out = OSnonlinear(outelem);
out.fcn = @(x) in1.fcn(x) * in2.fcn(x);
end
function out = mrdivide(in1, in2)
if isnumeric(in1)
in1 = OSnonlinear(in2.element, in1);
elem1 = in1.element;
elem2 = in2.element.cloneNode(true);
elseif isnumeric(in2)
elem1 = in1.element.cloneNode(true);
if elem1.getNodeName.equals('variable')
% variable divided by constant, fold into coef
outelem = elem1;
coef = str2double(outelem.getAttribute('coef'));
outelem.setAttribute('coef', sprintf('%.17g', coef/in2));
out = OSnonlinear(outelem);
return
end
in2 = OSnonlinear(in1.element, in2);
elem2 = in2.element;
else
elem1 = in1.element.cloneNode(true);
elem2 = in2.element.cloneNode(true);
end
document = elem1.getOwnerDocument;
if ~isequal(document, elem2.getOwnerDocument)
error('inputs must be expressions from same OSinstance')
end
outelem = document.createElement('divide');
outelem.appendChild(elem1);
outelem.appendChild(elem2);
out = OSnonlinear(outelem);
out.fcn = @(x) in1.fcn(x) / in2.fcn(x);
end
function out = mpower(in1, in2)
if isnumeric(in1)
in1 = OSnonlinear(in2.element, in1);
elem1 = in1.element;
elem2 = in2.element.cloneNode(true);
elseif isnumeric(in2)
if isequal(in2, 2)
% special case for square
out = univariate_fcn(in1, 'square');
out.fcn = @(x) in1.fcn(x)^2;
return
end
in2 = OSnonlinear(in1.element, in2);
elem2 = in2.element;
elem1 = in1.element.cloneNode(true);
else
elem1 = in1.element.cloneNode(true);
elem2 = in2.element.cloneNode(true);
end
document = elem1.getOwnerDocument;
if ~isequal(document, elem2.getOwnerDocument)
error('inputs must be expressions from same OSinstance')
end
outelem = document.createElement('power');
outelem.appendChild(elem1);
outelem.appendChild(elem2);
out = OSnonlinear(outelem);
out.fcn = @(x) in1.fcn(x) ^ in2.fcn(x);
end
function out = uplus(in1) % y = +x;
out = in1;
end
function out = univariate_fcn(in1, fcn)
elem1 = in1.element.cloneNode(true);
document = elem1.getOwnerDocument;
outelem = document.createElement(fcn);
outelem.appendChild(elem1);
out = OSnonlinear(outelem);
end
function out = uminus(in1)
if in1.element.getNodeName.equals('variable')
% unary minus of a variable, swap sign of coef
outelem = in1.element.cloneNode(true);
coefstr = outelem.getAttribute('coef').toCharArray;
if coefstr(1) == '-'
outelem.setAttribute('coef', coefstr(2:end));
else
outelem.setAttribute('coef', ['-'; coefstr]);
end
out = OSnonlinear(outelem);
else
out = univariate_fcn(in1, 'negate');
out.fcn = @(x) -in1.fcn(x);
end
end
function out = sqrt(in1)
out = univariate_fcn(in1, 'squareRoot');
out.fcn = @(x) sqrt(in1.fcn(x));
end
function out = log(in1)
out = univariate_fcn(in1, 'ln');
out.fcn = @(x) log(in1.fcn(x));
end
function out = log10(in1)
out = univariate_fcn(in1, 'log10');
out.fcn = @(x) log10(in1.fcn(x));
end
function out = exp(in1)
out = univariate_fcn(in1, 'exp');
out.fcn = @(x) exp(in1.fcn(x));
end
function out = sin(in1)
out = univariate_fcn(in1, 'sin');
out.fcn = @(x) sin(in1.fcn(x));
end
function out = cos(in1)
out = univariate_fcn(in1, 'cos');
out.fcn = @(x) cos(in1.fcn(x));
end
function out = tan(in1)
out = univariate_fcn(in1, 'tan');
out.fcn = @(x) tan(in1.fcn(x));
end
function out = asin(in1)
out = univariate_fcn(in1, 'arcsin');
out.fcn = @(x) asin(in1.fcn(x));
end
function out = acos(in1)
out = univariate_fcn(in1, 'arccos');
out.fcn = @(x) acos(in1.fcn(x));
end
function out = atan(in1)
out = univariate_fcn(in1, 'arctan');
out.fcn = @(x) atan(in1.fcn(x));
end
function out = sinh(in1)
out = univariate_fcn(in1, 'sinh');
out.fcn = @(x) sinh(in1.fcn(x));
end
function out = cosh(in1)
out = univariate_fcn(in1, 'cosh');
out.fcn = @(x) cosh(in1.fcn(x));
end
function out = tanh(in1)
out = univariate_fcn(in1, 'tanh');
out.fcn = @(x) tanh(in1.fcn(x));
end
function out = asinh(in1)
out = univariate_fcn(in1, 'arcsinh');
out.fcn = @(x) asinh(in1.fcn(x));
end
function out = acosh(in1)
out = univariate_fcn(in1, 'arccosh');
out.fcn = @(x) acosh(in1.fcn(x));
end
function out = atanh(in1)
out = univariate_fcn(in1, 'arctanh');
out.fcn = @(x) atanh(in1.fcn(x));
end
function out = cot(in1)
out = univariate_fcn(in1, 'cot');
out.fcn = @(x) cot(in1.fcn(x));
end
function out = coth(in1)
out = univariate_fcn(in1, 'coth');
out.fcn = @(x) coth(in1.fcn(x));
end
function out = acot(in1)
out = univariate_fcn(in1, 'arccot');
out.fcn = @(x) acot(in1.fcn(x));
end
function out = acoth(in1)
out = univariate_fcn(in1, 'arccoth');
out.fcn = @(x) acoth(in1.fcn(x));
end
function out = sec(in1)
out = univariate_fcn(in1, 'sec');
out.fcn = @(x) sec(in1.fcn(x));
end
function out = sech(in1)
out = univariate_fcn(in1, 'sech');
out.fcn = @(x) sech(in1.fcn(x));
end
function out = asec(in1)
out = univariate_fcn(in1, 'arcsec');
out.fcn = @(x) asec(in1.fcn(x));
end
function out = asech(in1)
out = univariate_fcn(in1, 'arcsech');
out.fcn = @(x) asech(in1.fcn(x));
end
function out = csc(in1)
out = univariate_fcn(in1, 'csc');
out.fcn = @(x) csc(in1.fcn(x));
end
function out = csch(in1)
out = univariate_fcn(in1, 'csch');
out.fcn = @(x) csch(in1.fcn(x));
end
function out = acsc(in1)
out = univariate_fcn(in1, 'arccsc');
out.fcn = @(x) acsc(in1.fcn(x));
end
function out = acsch(in1)
out = univariate_fcn(in1, 'arccsch');
out.fcn = @(x) acsch(in1.fcn(x));
end
function out = erf(in1)
out = univariate_fcn(in1, 'erf');
out.fcn = @(x) erf(in1.fcn(x));
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment