Last active
December 25, 2015 01:59
-
-
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% 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