Commit 22cc729a authored by Jakob Gabriel's avatar Jakob Gabriel Committed by Ferdinand Fischer
Browse files

quantity.Symbolic.subs: rewritten to work with quantity.Domain

parent c6caf266
......@@ -256,8 +256,8 @@ classdef Symbolic < quantity.Function
c = cat@quantity.Discrete(dim, objCell{:});
end % cat()
function solution = subs(obj, gridName, values)
%% SUBS substitues gridName and values
function solution = subs(obj, gridName2Replace, values)
% SUBS substitues gridName and values
% solution = subs(obj, DOMAIN) can be used to change the grid
% of this quantity. The domains with the same domain name as
% DOMAIN will be replaced with the corresponding grid in
......@@ -275,124 +275,78 @@ classdef Symbolic < quantity.Function
% quantity.Domain objects. The NEWDOMAIN must be an
% object-array of quantity.Domain.
if isa(gridName, 'quantity.Domain')
if isa(gridName2Replace, 'quantity.Domain')
if nargin == 2
gridName = {gridName.name};
values = {gridName.grid};
gridName2Replace = {gridName2Replace.name};
values = {gridName2Replace.grid};
else
gridName = {gridName.name};
gridName2Replace = {gridName2Replace.name};
end
end
gridName = misc.ensureString(gridName);
gridName2Replace = misc.ensureString(gridName2Replace);
if nargin == 3 && isa(values, 'quantity.Domain')
% replacement of the grid AND the gridName
% 1) replace the grid
solution = obj.changeGrid( {values.grid}, gridName );
solution = obj.changeGrid( {values.grid}, gridName2Replace );
% 2) replace the name
solution = solution.subs( gridName, {values.name} );
solution = solution.subs( gridName2Replace, {values.name} );
return
else
values = misc.ensureIsCell(values);
for it = 1 : numel(values)
% for later strcmp usage, values must be a cell-array with only
% numeric or char elements.
if isstring(values{it})
values{it} = char(values{it});
end
end % for it = 1 : numel(values)
end
isNumericValue = cellfun(@isnumeric, values);
if any((cellfun(@(v) numel(v(:)), values)>1) & isNumericValue)
error('only implemented for one value per grid');
end
numericValues = values(isNumericValue);
if ~isempty(numericValues) && numel(obj(1).gridName) == numel(numericValues)
% if all grids are evaluated, solution is a double array.
solution = reshape(obj.on(numericValues), size(obj));
else
% evaluate numeric values
subsGrid = obj(1).grid;
selectRemainingGrid = false(1, numel(obj(1).grid));
for currentGridName = gridName(isNumericValue)
selectGrid = strcmp(obj(1).gridName, currentGridName);
subsGrid{selectGrid} = values{strcmp(gridName, currentGridName)};
selectRemainingGrid = selectRemainingGrid | selectGrid;
values = misc.ensureIsCell(values);
isNumericValue = false(numel(values), 1);
for it = 1 : numel(values)
% check which values are substitutions with numerical values in the domain
if isnumeric(values{it})
isNumericValue(it) = true;
end
newGrid = obj(1).grid(~selectRemainingGrid);
newGridName = obj(1).gridName(~selectRemainingGrid);
for it = 1 : numel(values)
if ~isNumericValue(it) && ~isempty(obj(1).gridName(~selectRemainingGrid))
% check if there is a symbolic value and if this value exists in the object
if isstring( values{it} ) || ischar( values{it} )
newGridName( strcmp(obj(1).gridName(~selectRemainingGrid), gridName(it)) ) ...
= values{it};
elseif isa(values{it}, 'sym')
gridNameTemp = symvar(values{it});
assert(numel(gridNameTemp) == 1, 'replacing one gridName with 2 gridName is not supported');
newGridName{strcmp(obj(1).gridName(~selectRemainingGrid), gridName(it))} ...
= char(gridNameTemp);
end % for it = 1 : numel(values)
% new domain is the old one without the domains that are evaluated at specific numeric
% values. Furthermore, the other domains are renamed.
newDomain = obj(1).domain.remove(gridName2Replace(isNumericValue));
if any(~isNumericValue)
% rename domains that are affected by symbolic substitution
gridName2ReplaceSymbolicOld = gridName2Replace(~isNumericValue);
gridName2ReplaceSymbolicNew = string(values(~isNumericValue));
resultingName = replace([newDomain.name], gridName2ReplaceSymbolicOld, gridName2ReplaceSymbolicNew);
if misc.isunique(resultingName)
newDomain = newDomain.rename(gridName2ReplaceSymbolicNew, gridName2ReplaceSymbolicOld);
else % complicated case, for instance f(x, y).subs("x", "y") = f(y, y)
% for this, join is used.
for it = 1 : numel(gridName2ReplaceSymbolicNew)
if any(strcmp([newDomain.name], gridName2ReplaceSymbolicNew(it)))
% remove domain to be removed and join it with the single renamed domain.
newDomain = join(newDomain.remove(gridName2ReplaceSymbolicOld(it)), ...
newDomain.find(gridName2ReplaceSymbolicOld(it)).rename(...
gridName2ReplaceSymbolicNew(it)));
else
error(['value{', num2str(it), '} is of unsupported type']);
newDomain = newDomain.rename(...
gridName2ReplaceSymbolicNew(it), gridName2ReplaceSymbolicOld(it));
end
end
end % for it = 1 : numel(gridName2ReplaceSymbolicNew)
end
symbolicSolution = subs(obj.sym(), cellstr(gridName), values);
if isempty(symvar(symbolicSolution(:)))
% take the new values that are not numeric as the new
% variables:
newGridName = unique(newGridName, 'stable');
newGrid = cell(1, numel(newGridName));
charValues = cell(0);
for it = 1 : numel(values)
if isstring(values{it}) || ischar(values{it})
charValues{end+1} = char(values{it});
end
end
for it = 1 : numel(newGridName)
if ~isempty(charValues) && any(contains(charValues, newGridName{it}))
newGrid{it} = obj.gridOf(gridName( strcmp(newGridName{it}, values) ));
else
newGrid{it} = obj.gridOf(newGridName{it});
end
end
solution = quantity.Symbolic(double(symbolicSolution), ...
'grid', newGrid, 'gridName', newGridName, 'name', obj(1).name);
else
% before creating a new quantity, it is checked that
% newGridName is unique. If there are non-unique
% gridName, multiple are removed and the finest grid
% from newGrid is taken.
uniqueGridName = unique(newGridName, 'stable');
if numel(newGridName) == numel(uniqueGridName)
solution = quantity.Symbolic(symbolicSolution, ...
'grid', newGrid, 'gridName', newGridName, 'name', obj(1).name);
else
uniqueGrid = cell(1, numel(uniqueGridName));
for it = 1 : numel(uniqueGrid)
gridCandidatesTemp = newGrid(...
strcmp(uniqueGridName{it}, newGridName));
for jt = 1 : numel(gridCandidatesTemp)
if ~isempty(uniqueGrid{it})
assert(uniqueGrid{it}(1) == gridCandidatesTemp{jt}(1) ...
&& uniqueGrid{it}(end) == gridCandidatesTemp{jt}(end), ...
'grids must have same domain');
end
if isempty(uniqueGrid{it}) || ...
numel(gridCandidatesTemp{jt}) > numel(uniqueGrid{it})
uniqueGrid{it} = gridCandidatesTemp{jt};
end
end
end
solution = quantity.Symbolic(symbolicSolution, ...
'grid', uniqueGrid, 'gridName', uniqueGridName, 'name', obj(1).name);
% convert elements of values to symbolic expressions
for it = 1 : numel(values)
if ~isnumeric(values{it})
values{it} = sym(values{it});
end
end
end % for it = 1 : numel(values)
end
if numel(newDomain) > 0
solution = quantity.Symbolic(...
subs(obj.sym(), sym(gridName2Replace), values), ...
newDomain, ...
'name', obj(1).name);
else
solution = double(subs(obj.sym(), sym(gridName2Replace), values));
end
end % subs()
......
......@@ -1241,9 +1241,9 @@ bzZeta = cos(zGrid * pi) + cos(zetaGrid * pi);
Z = quantity.Domain("z", z);
Zeta = quantity.Domain("zeta", zeta);
AB = quantity.Discrete({a, b}, Z.copyAndRename("blub"));
AB = quantity.Discrete({a, b}, Z.rename("blub"));
A = quantity.Discrete({a}, Z);
ALr = quantity.Discrete({aLr}, Zeta.copyAndRename("z"));
ALr = quantity.Discrete({aLr}, Zeta.rename("z"));
B = quantity.Discrete({b}, Z);
C = quantity.Discrete({C}, Zeta);
AZZETA = quantity.Discrete({azZeta}, [Z, Zeta]);
......
......@@ -230,10 +230,10 @@ syms z zeta eta e a
myGrid = linspace(0, 1, 7);
myDomain(1) = quantity.Domain("z", myGrid);
myDomain(2) = myDomain(1).copyAndRename("zeta");
myDomain(3) = myDomain(1).copyAndRename("eta");
myDomain(4) = myDomain(1).copyAndRename("e");
myDomain(5) = myDomain(1).copyAndRename("a");
myDomain(2) = myDomain(1).rename("zeta");
myDomain(3) = myDomain(1).rename("eta");
myDomain(4) = myDomain(1).rename("e");
myDomain(5) = myDomain(1).rename("a");
obj = quantity.Symbolic([z*zeta, eta*z; e*a, a], myDomain);
......@@ -874,7 +874,7 @@ function testSubs2(tc)
tc.verifyEqual(Id.on(), Id.subs("z", "zeta").on(), 'AbsTol', 10*eps);
end % testSubs2()
function testSubs(testCase)
function testSubs(tc)
%%
% init
syms x y z w
......@@ -901,9 +901,9 @@ Z0 = quantity.Domain('z', 0);
fOfz = f.subs([X, Y], [Z Z]);
fOfyx = f.subs({'x', 'y'}, {'w', 'x'});
testCase.verifyEqual(Ff1, fOf1);
testCase.verifyEqual(Ffz.sym(), fOfz.sym());
testCase.verifyEqual(Fyx.sym(), fOfyx.sym());
tc.verifyEqual(Ff1, fOf1);
tc.verifyEqual(Ffz.sym(), fOfz.sym());
tc.verifyEqual(Fyx.sym(), fOfyx.sym());
%%
syms z zeta
......@@ -911,28 +911,15 @@ assume(z>0 & z<1); assume(zeta>0 & zeta<1);
F = quantity.Symbolic(zeros(1), ...
[quantity.Domain.defaultDomain(3, "z"), quantity.Domain.defaultDomain(3, "zeta")]);
Feta = F.subs('z', 'eta');
testCase.verifyEqual(Feta(1).gridName, ["eta", "zeta"]);
tc.verifyEqual(Feta(1).gridName, ["eta", "zeta"]);
%%
fMessy = quantity.Symbolic(x^1*y^2*z^4*w^5, [X, Y, Z, W]);
fMessyA = fMessy.subs({'x', 'y', 'z', 'w'}, {'a', 'a', 'a', 'a'});
fMessyYY = fMessy.subs({'w', 'x', 'z'}, {'xi', 'y', 'y'});
testCase.verifyEqual(fMessyA.gridName, "a");
testCase.verifyEqual(fMessyA.grid, {linspace(0, 1, 11)'});
testCase.verifyEqual(fMessyYY.gridName, ["y", "xi"]);
testCase.verifyEqual(fMessyYY.grid, {linspace(0, 1, 11)', linspace(0, 1, 3)'});
% % sub multiple numerics -> not implemented yet
% f11 = f.subs('x', [1; 2]);
% f1 = f.subs('x', 1);
% f2 = f.subs('x', 2);
% testCase.verifyEqual(reshape(f11(1,:,:).sym(), size(f)), fOf1);
% testCase.verifyEqual(reshape(f11(2,:,:).sym(), size(f)), f2.sym());
%
% % sub multiple multiple variables
% f1232 = f.subs({'x', 'y'}, {[1; 2], [3; 2]});
% f13 = f.subs({'x', 'y'}, {1, 3});
% f22 = f.subs({'x', 'y'}, {2, 2});
% testCase.verifyEqual(reshape(f1232(1,:,:), size(f)), f22);
% testCase.verifyEqual(reshape(f1232(2,:,:), size(f)), f13);
end
tc.verifyEqual(fMessyA.gridName, "a");
tc.verifyEqual(fMessyA.grid, {linspace(0, 1, 11)'});
tc.verifyEqual(fMessyYY.gridName, ["y", "xi"]);
tc.verifyEqual(fMessyYY.grid, {linspace(0, 1, 11)', linspace(0, 1, 3)'});
end % testSubs()
......@@ -7,3 +7,4 @@
***.aux
***.log
.PowerFolder/
*.asv
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