Commit e44a1e6d authored by Jakob Gabriel's avatar Jakob Gabriel
Browse files

quantity.Discrete.subsNumeric: new

parent af4ff393
......@@ -1043,14 +1043,114 @@ classdef (InferiorClasses = {?quantity.Symbolic}) Discrete ...
%
% d) string-arrays, then the domain of the domains specified by oldDomainName are
% renamed with the new names.
%
% The substitution is performed iteratively, starting with the first elements of
% oldDomainName and varargin.
assert(isstring(oldDomainName), "oldDomainName must be a string-array.");
newValues = quantity.Discrete.subsParser(oldDomainName, varargin);
% Now, the first pair of oldDomainName{1}, newValues{1} is substituted. At the end,
% subs is called again for remaining values (if there are remaining values).
if isstring(newValues{1})
% if newValues{1} is a string, it is converted in a domain, to use the same
% implementation as for quantity.Domain-objects in newValues.
newValues{1} = obj(1).domain.find(oldDomainName{1}).rename(newValues{1}, oldDomainName{1});
end
if isnumeric(newValues{1})
solution = obj.subsNumeric(oldDomainName{1}, newValues{1});
else
% newValues{1} is a quantity.Domain-object.
if any(strcmp(newValues{1}, oldDomainName(2:end)))
% in the case if a quantity f(z, zeta) should be
% substituted like subs(f, {z, zeta}, {zeta, z})
% this would cause an error, since after the first
% substituion subs(f, z, zeta) the result would be
% f(zeta, zeta) -> the 2nd subs(f, zeta, z) will
% result in f(z, z) and not in f(zeta, z) as
% intended. This is solved, by an additonal
% substitution:
% f.subs(z,zetabackUp).subs(zeta,z).subs(zetabackUp,zeta)
newValues{end+1} = newValues{1};
oldDomainName{end+1} = [oldDomainName{1}, 'backUp'];
newValues{1} = oldDomainName{end};
end
if isequal(newValues{1}, oldDomainName{1})
% replace with same variable... everything stays the
% same.
% Do not use "return", since, later subs might need to be
% called recursively!
newValue = obj.on();
elseif any(strcmp(newValues{1}, obj(1).gridName))
% if for a quantity f(z, zeta) this method is
% called with subs(f, zeta, z), then g(z) = f(z, z)
% results, hence the dimensions z and zeta are
% merged.
domainIndices = [obj(1).domain.gridIndex(oldDomainName{1}), ...
obj(1).domain.gridIndex(newValues{1})];
newDomainForOn = obj(1).domain;
if obj(1).domain(domainIndices(1)).n > obj(1).domain(domainIndices(2)).n
newDomainForOn(domainIndices(2)) = quantity.Domain(...
newDomainForOn(domainIndices(2)).name, ...
newDomainForOn(domainIndices(1)).grid);
elseif obj(1).domain(domainIndices(1)).n < obj(1).domain(domainIndices(2)).n
newDomainForOn(domainIndices(1)) = quantity.Domain(...
newDomainForOn(domainIndices(1)).name, ...
newDomainForOn(domainIndices(2)).grid);
end
newValue = misc.diagNd(obj.on(newDomainForOn), domainIndices);
newDomain = [newDomainForOn(domainIndices(2)), ...
newDomainForOn(all(1:1:numel(newDomainForOn) ~= domainIndices(:)))];
else
% this is the default case. just grid name is changed.
%newDomain = obj(1).domain;
newDomain(obj(1).domain.gridIndex(oldDomainName{1})) = ...
quantity.Domain(newValues{1}, ...
obj(1).domain(obj(1).domain.gridIndex(oldDomainName{1})).grid);
newValue = obj.on();
end
end % if-else
if numel(oldDomainName) > 1
solution = solution.subs(oldDomainName(2:end), newValues(2:end));
end
end % subs()
function solution = subsNumeric(obj, oldDomainName, value)
% subsNumeric Numeric substitution.
%
% subsNumeric(obj, oldDomainName, value) replaces the old domains of obj specified by the
% string-array oldDomainName with the numeric values in value.
%
% Example: subs(f(z, zeta, t), ["z", "zeta"], [1, 2]) = f(1, 2, t) = g(t).
arguments
obj quantity.Discrete;
oldDomainName (:, 1) string;
value (:, 1) double;
end % arguments
assert(numel(oldDomainName) == numel(value), "for every domain to be substituted, ", ...
"there must be defined one numeric scalar value");
numberDomains = quantity.Domain(oldDomainName(1), value(1));
for it = 2 : numel(value)
numberDomains = [numberDomains, quantity.Domain(oldDomainName(it), value(it))];
end
otherDomains = obj(1).domain.remove(numberDomains);
solution = obj.on([otherDomains, numberDomains]);
if isempty(otherDomains)
solution = reshape(solution, size(obj));
else
solution = quantity.Discrete(solution, otherDomains, "name", obj(1).name);
end
end % subsNumeric()
% function solution = subs(obj, gridName2Replace, values)
% % SUBS substitute variables of a quantity
......@@ -2757,18 +2857,24 @@ classdef (InferiorClasses = {?quantity.Symbolic}) Discrete ...
% subsParser is a helper function to parse the inputs of subs. In this method, the
% elements of the newValues-cell-array are splitted, such that there is one cell element
% for every oldDomainName. Specificly, string-arrays and domain-arrays in newValues are
% split, while numeric-arrays remain unchanged.
% split, while numeric-scalars remain unchanged and numeric-arrays are replaced by
% domains.
newValuesSorted = cell(size(oldDomainName));
sortedIdx = 1;
for it = 1 : numel(newValues)
if isnumeric(newValues{it}) && isvector(newValues{it})
newValuesSorted(sortedIdx) = newValues{it};
if isscalar(newValues{it})
newValuesSorted{sortedIdx} = newValues{it};
else % isvector(newValues{it}) == true
newValuesSorted{sortedIdx} = ...
quantity.Domain(oldDomainName(sortedIdx), newValues{it});
end
sortedIdx = sortedIdx + 1;
elseif isstring(newValues{it}) || isa(newValues{it}, "quantity.Domain")
for jt = 1 : numel(newValues{it})
newValuesSorted(sortedIdx) = newValues{it}(jt);
newValuesSorted{sortedIdx} = newValues{it}(jt);
sortedIdx = sortedIdx + 1;
end
......@@ -2779,8 +2885,8 @@ classdef (InferiorClasses = {?quantity.Symbolic}) Discrete ...
end % if-else
end % for it = 1 : numel(newValues)
assert(sortedIdx == numel(oldDomainName), "number of elements in oldDomainName and " ...
"in varargin must be equal when calling subs(obj, oldDomainName, varargin)");
assert(sortedIdx-1 == numel(oldDomainName), "number of elements in oldDomainName and " ...
+ "in varargin must be equal when calling subs(obj, oldDomainName, varargin)");
end % subsParser()
......
......@@ -4,6 +4,47 @@ function [tests] = testDiscrete()
tests = functiontests(localfunctions);
end
function testSubsNumeric(tc)
z = quantity.Domain("z", linspace(0, 1, 5));
zeta = quantity.Domain("zeta", linspace(0, 1, 4));
t = quantity.Domain("t", linspace(0, 1, 6));
% quanScalar = z.Discrete() + 1 + zeta.Discrete() * t.Discrete();
% tc.verifyEqual(quanScalar.subsNumeric(["z", "t"], [0, 0]).on(), ones(zeta.n, 1));
% tc.verifyEqual(quanScalar.subsNumeric(["t", "z", "zeta"], [0.1, 0.2, 0.3]), 0.2 + 1 + 0.3 * 0.1);
%
% quanMatrix = quantity.Discrete(quantity.Symbolic(...
% [sym("z") + 1 + sym("zeta") * sym("t"), 1; ...
% sym("z").^2 + sym("t"), -sym("zeta")], [zeta, t, z]));%[quanScalar, 1; z.Discrete()*z.Discrete() + t.Discrete, -zeta.Discrete];
% tc.verifyEqual(quanMatrix.subsNumeric(["z", "zeta", "t"], [0.1, 0.2, 0.3]), ...
% [0.1 + 1 + 0.2 * 0.3, 1; 0.1^2 + 0.3, -0.2]);
% tc.verifyEqual(quanMatrix.subsNumeric(["z", "zeta", "t"], [0, 0, 0]), [1, 1; 0, 0]);
% tc.verifyEqual(quanMatrix.subsNumeric(["z", "zeta", "t"], [1, 1, 1]), [3, 1; 2, -1]);
% tc.verifyEqual(quanMatrix(1, 1).subsNumeric(["z", "zeta", "t"], [0.1, 0.2, 0.3]), 0.1 + 1 + 0.2 * 0.3);
thisSym = sym("z") + 1 + sym("zeta") * sym("t");
quanMatrix11 = quantity.Symbolic(thisSym, [zeta, t, z]);
tc.verifyEqual(quanMatrix11.subsNumeric(["z", "zeta", "t"], [0.1, 0.2, 0.3]), 0.1 + 1 + 0.2 * 0.3);
tc.verifyEqual(quanMatrix11.on({0.2, 0.3, 0.1}), 0.1 + 1 + 0.2 * 0.3);
tc.verifyEqual(double(subs(subs(subs(thisSym, "z", 0.1), "zeta", 0.2), "t", 0.3)), 0.1 + 1 + 0.2 * 0.3, "AbsTol", 10*eps);
end % testSubsNumeric()
function testSubsParser(tc)
z = quantity.Domain("z", [0, 1, 2]);
zeta = quantity.Domain("zeta", [0, 1, 2]);
result1 = quantity.Discrete.subsParser(["z", "zeta", "eta", "z"], {["t1", "t2"], 1, linspace(0, 1, 11)});
tc.verifyEqual(result1, {"t1", "t2", 1, quantity.Domain("z", linspace(0, 1, 11))});
result2 = quantity.Discrete.subsParser(["z", "zeta", "eta", "z"], {["t1"; "t2"], [z; zeta]});
tc.verifyEqual(result2, {"t1", "t2", z, zeta});
tc.verifyError(@() quantity.Discrete.subsParser(["z", "zeta"], {1}), "");
tc.verifyError(@() quantity.Discrete.subsParser(["z", "zeta"], {1, ones(2)}), "");
end % testSubsParser()
function testSortAndIssorted(tc)
z = quantity.Domain("z", linspace(0, 1, 4));
quanSymbolic = quantity.Symbolic([-sym("z")-0.5, 2 + sym("z"), 3.2, -2, 0, 3.5], z);
......
......@@ -4,6 +4,57 @@ function [tests ] = testSymbolic()
tests = functiontests(localfunctions());
end
function testOn2(tc)
zeta = quantity.Domain("zeta", linspace(0, 1, 4));
t = quantity.Domain("t", linspace(0, 1, 4));
thisSym = sym("zeta") + sym("t");
quan = quantity.Symbolic(thisSym, [zeta, t]);
solution = 0.2 + 0.3; % this obtained by manual calculation
% verify solution
tc.verifyEqual(double(subs(subs(thisSym, "zeta", 0.2), "t", 0.3)), solution, "AbsTol", 10*eps);
% test on with numeric values only
tc.verifyEqual(quan.on({0.2, 0.3}), solution);
% test on with domain
tc.verifyEqual(quan.on([quantity.Domain("zeta", 0.2), quantity.Domain("t", 0.3)]), solution);
end % testOn2()
function testOn2b(tc)
zeta = quantity.Domain("zeta", linspace(0, 1, 4));
t = quantity.Domain("t", linspace(0, 1, 4));
thisSym = sym("zeta") + sym("t");
quan = quantity.Symbolic(thisSym, [t, zeta]);
solution = 0.2 + 0.3; % this obtained by manual calculation
% verify solution
tc.verifyEqual(double(subs(subs(thisSym, "zeta", 0.2), "t", 0.3)), solution, "AbsTol", 10*eps);
% test on with numeric values only
tc.verifyEqual(quan.on({0.3, 0.2}), solution);
% test on with domain
tc.verifyEqual(quan.on([quantity.Domain("zeta", 0.2), quantity.Domain("t", 0.3)]), solution);
end % testOn2()
function testOn3(tc)
z = quantity.Domain("z", linspace(0, 1, 4));
t = quantity.Domain("t", linspace(0, 1, 4));
thisSym = sym("z") + sym("t");
quan = quantity.Symbolic(thisSym, [z, t]);
solution = 0.2 + 0.3; % this obtained by manual calculation
% verify solution
tc.verifyEqual(double(subs(subs(thisSym, "z", 0.2), "t", 0.3)), solution, "AbsTol", 10*eps);
% test on with numeric values only
tc.verifyEqual(quan.on({0.2, 0.3}), solution);
% test on with domain
tc.verifyEqual(quan.on([quantity.Domain("z", 0.2), quantity.Domain("t", 0.3)]), solution);
end % testOn2()
function testDiffOfConstants(tc)
% unittest to fix a bug...
z = quantity.Domain("z", linspace(0, 1, 4));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment