From a76a2587cd1da0ca4e31b96df9787e259db839d0 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 17 May 2026 19:11:52 +0200 Subject: [PATCH 01/24] Make jump field in sol output a logical array --- toolbox/internal/solving/solveODE_assembleOutput.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/internal/solving/solveODE_assembleOutput.m b/toolbox/internal/solving/solveODE_assembleOutput.m index a70dd83..902d2ae 100644 --- a/toolbox/internal/solving/solveODE_assembleOutput.m +++ b/toolbox/internal/solving/solveODE_assembleOutput.m @@ -16,7 +16,7 @@ numSwitches = length(data.SWP_detection.switchingpoints); switches = zeros(1, numSwitches); -jumps = zeros(1, numSwitches); +jumps = false(1, numSwitches); for i = 1:numSwitches switches(1, i) = data.SWP_detection.switchingpoints{i}; From c90668fb093cd5140c1e7e0d83353170ff8d3e85 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 17 May 2026 19:12:37 +0200 Subject: [PATCH 02/24] Set datahandle model number directly when retrieving RHS for model --- toolbox/internal/sensitivities/getRhsFromModelNum.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/toolbox/internal/sensitivities/getRhsFromModelNum.m b/toolbox/internal/sensitivities/getRhsFromModelNum.m index c1abfa4..ef853d7 100644 --- a/toolbox/internal/sensitivities/getRhsFromModelNum.m +++ b/toolbox/internal/sensitivities/getRhsFromModelNum.m @@ -43,5 +43,7 @@ return end -% Default case, just return the preprocessed RHS +% Default case, just return the preprocessed RHS and set the model number for correct ctrlif branching. +data.computeSensitivity.modelStage = modelNum; +datahandle.setData(data); rhs = data.integratorSettings.preprocessed_rhs; From 32c7484c43f85e4c52c014b997d27633ce92bfb5 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 17 May 2026 19:14:45 +0200 Subject: [PATCH 03/24] WIP: Add prototype for new sensitivity solver --- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 138 ++++++++++++++++++ .../_sensNew/@IFDIFFSensitivity/solveVde.m | 17 +++ .../_sensNew/applySensitivitySwitchUpdate.m | 94 ++++++++++++ toolbox/internal/_sensNew/finiteDifference.m | 39 +++++ toolbox/internal/_sensNew/testSensNew.m | 49 +++++++ toolbox/internal/_sensNew/vdeRhs.m | 18 +++ 6 files changed, 355 insertions(+) create mode 100644 toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m create mode 100644 toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m create mode 100644 toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m create mode 100644 toolbox/internal/_sensNew/finiteDifference.m create mode 100644 toolbox/internal/_sensNew/testSensNew.m create mode 100644 toolbox/internal/_sensNew/vdeRhs.m diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m new file mode 100644 index 0000000..5eebcab --- /dev/null +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -0,0 +1,138 @@ +classdef IFDIFFSensitivity + %IFDIFFSENSITIVITY Summary of this class goes here + % Detailed explanation goes here + + properties + datahandle + solution + Uy + Up + UyAccumulated + UpAccumulated + GySol = {} + GpSol + parameters + tspan + switches + switchesY + switchesLeft + switchesLeftY + dimy + dimp + fdStep + modelBoundaries + integrator + integratorOptions + dirY + dirP + switchingFunctions + jumpFunctions + end + + methods + function this = IFDIFFSensitivity(datahandle, sol, dirY, dirP) + this.datahandle = datahandle; + this.solution = sol; + data = datahandle.getData(); + this.switchingFunctions = data.SWP_detection.switchingFunction; + this.jumpFunctions = data.SWP_detection.jumpFunction; + + this.parameters = data.SWP_detection.parameters; + this.dimy = length(data.SWP_detection.initialvalues); + this.dimp = length(this.parameters); + + this.tspan = data.SWP_detection.tspan; + this.switches = sort(sol.switches); + this.modelBoundaries = [this.tspan(1), this.switches, this.tspan(end)]; + + [isSwitchInSol, switchesIdx] = ismember(this.switches, sol.x); + if ~all(isSwitchInSol) + error('IFDIFF:Sensitivity:SwitchNotInSol', ... + 'Switch at t=%.10g not found in solution time points.', ... + this.switches(find(~isSwitchInSol, 1))); + end + this.switchesY = sol.y(:, switchesIdx); + + this.switchesLeft = this.switches; + this.switchesLeftY = this.switchesY; + this.switchesLeft(sol.jumps) = sol.x(switchesIdx(sol.jumps) - 1); + this.switchesLeftY(:, sol.jumps) = sol.y(:, switchesIdx(sol.jumps) - 1); + + this.fdStep = generateFDstep(this.dimy, this.dimp); + + this.integrator = data.integratorSettings.numericIntegrator; + this.integratorOptions = data.integratorSettings.options; + + if isempty(dirY) + dirY = eye(this.dimy); + end + if isempty(dirP) + dirP = eye(this.dimp); + end + this.dirY = dirY; + this.dirP = dirP; + end + + function this = eval(this, timepoints) + [t, ~, idxTimepointsUndoSort] = unique(timepoints); + + if t(1) < this.tspan(1) || t(end) > this.tspan(end) + error('IFDIFF:Sensitivity:TimepointOutOfBounds', ... + ['Requested sensitivity evaluation timepoint is not contained within,', ... + 'the solution interval of the IVP.']); + end + + idxModelStart = 1; + % Find the switch, that would come after the last evaluation timepoint + idxModelEnd = find(t(end) <= this.modelBoundaries, 1) - 1; + + tstart = this.tspan(1); + sens = [this.dirY, zeros(this.dimy, size(this.dirP, 2))]; + nDirY = size(this.dirY, 2); + if idxModelEnd > idxModelStart + fMinus = getRhsFromModelNum(this.datahandle, idxModelStart); + end + for idxModel=idxModelStart:idxModelEnd-1 + tend = this.switchesLeft(idxModel); + sol = this.solveVde(idxModel, [tstart, tend], sens, nDirY, this.dirP); + tstart = this.switches(idxModel); + this.GySol{idxModel} = sol; + + sens = reshape(sol.y(:, end), this.dimy, []); + + % Update (not on last iteration) + yMinus = this.switchesLeftY(:, idxModel); + yPlus = this.switchesY(:, idxModel); + fPlus = getRhsFromModelNum(this.datahandle, idxModel + 1); + sigma = this.switchingFunctions{idxModel}; + jump = this.jumpFunctions{idxModel}; + h = 1e-6; + sigmat = @(t, y, p, v) finiteDifference(@(x) sigma([], x, y, p), t, h, v); + sigmay = @(t, y, p, v) finiteDifference(@(x) sigma([], t, x, p), y, h, v); + sigmap = @(t, y, p, v) finiteDifference(@(x) sigma([], t, y, x), p, h, v); + if isempty(jump) + jumpt = []; + jumpy = []; + jumpp = []; + else + jumpt = @(t, y, p, v) finiteDifference(@(x) jump([], x, y, p), t, h, v); + jumpy = @(t, y, p, v) finiteDifference(@(x) jump([], t, x, p), y, h, v); + jumpp = @(t, y, p, v) finiteDifference(@(x) jump([], t, y, x), p, h, v); + end + sens = applySensitivitySwitchUpdate( ... + sens, this.dirP, size(this.dirY, 2), ... + tend, tstart, yMinus, yPlus, this.parameters, ... + @(t,y,p) fMinus(this.datahandle,t,y,p), @(t,y,p) fPlus(this.datahandle,t,y,p), ... + sigmat, sigmay, sigmap, ... + jumpt, jumpy, jumpp); + fMinus = fPlus; + end + idxModel = idxModel + 1; + tend = t(end); + sol = this.solveVde(idxModel, [tstart, tend], sens, nDirY, this.dirP); + this.GySol{idxModel} = sol; + end + + sol = solveVde(this, idxModel, tspan, initialValues, nDirY, initialDirP) + end +end diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m new file mode 100644 index 0000000..b55343c --- /dev/null +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m @@ -0,0 +1,17 @@ +function sol = solveVde(this, idxModel, tspan, initialValues, nDirY, initialDirP) +rhs = getRhsFromModelNum(this.datahandle, idxModel); +rhs = @(t, y, p) rhs(this.datahandle, t, y, p); + + +h = 1e-6; +fDyPartial = @(t, y, p, v) finiteDifference(@(x) rhs(t, x, p), y, h, v); +if isempty(initialDirP) + fDpPartial = []; +else + fDpPartial = @(t, y, p) finiteDifference(@(x) rhs(t, y, x), p, h, initialDirP); +end + +rhsVde = @(t, G) vdeRhs(t, G, this.solution, this.parameters, nDirY, fDyPartial, fDpPartial); +initialValues = initialValues(:); +sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); +end diff --git a/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m b/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m new file mode 100644 index 0000000..44482db --- /dev/null +++ b/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m @@ -0,0 +1,94 @@ +function update = applySensitivitySwitchUpdate( ... + sens, pInitialDir, nDirY, ... + tMinus, tPlus, yMinus, yPlus, p, ... + fMinusFunc, fPlusFunc, ... + sigmaDtPartialFunc, sigmaDyPartialFunc, sigmaDpPartialFunc, ... + jumpDtPartialFunc, jumpDyPartialFunc, jumpDpPartialFunc) + +update = sens; +[dimy, nDir] = size(sens); +% Determine which columns contain parameter sensitivities and which initial value sensitivities. +nDirP = nDir - nDirY; +hasParameter = nDirP > 0; + +if ~isempty(fPlusFunc) || ~isempty(jumpDyPartialFunc) + fMinus = fMinusFunc(tMinus, yMinus, p); +else + fMinus = []; +end + +% Compute: f_m - f_p - jump_t - jump_y*f_m +% Also apply updates: s += jump_y*s; for parameters additionally do s += jump_p*dir_p +switchDiscontinuity = zeros(dimy, 1); +if ~isempty(fPlusFunc) + fPlus = fPlusFunc(tPlus, yPlus, p); + switchDiscontinuity = switchDiscontinuity + fPlus - fMinus; +end +if ~isempty(jumpDtPartialFunc) + switchDiscontinuity = switchDiscontinuity - jumpDtPartialFunc(tMinus, yMinus, p, []); +end +if ~isempty(jumpDyPartialFunc) + % Evaluate jump_y in direction of sens and fMinus in one call for efficiency. + % Last column belongs to fMinus. + jumpDyPartial = jumpDyPartialFunc(tMinus, yMinus, p, [sens, fMinus]); + update = update + jumpDyPartial(:, 1:end-1); + switchDiscontinuity = switchDiscontinuity - jumpDyPartial(:, end); +end +if hasParameter && ~isempty(jumpDpPartialFunc) + % Apply only to parameter sensitivities. + update(:, nDirY+1:end) = update(:, nDirY+1:end) + jumpDpPartialFunc(tMinus, yMinus, p, pInitialDir); +end +if all(switchDiscontinuity == 0) + % Remaining outer product term would be zero, so we are done here. + return +end + +% Compute: sigma_y*s + sigma_p*dir_p +switchCoeffs = zeros(1, nDir); +if ~isempty(sigmaDyPartialFunc) + switchCoeffs = switchCoeffs + sigmaDyPartialFunc(tMinus, yMinus, p, sens); +end +if hasParameter && ~isempty(sigmaDpPartialFunc) + % Apply only to parameter sensitivity components + switchCoeffs(nDirY+1:end) = switchCoeffs(nDirY+1:end) + sigmaDpPartialFunc(tMinus, yMinus, p, pInitialDir); +end +if all(switchCoeffs == 0) + % Remaining outer product term would be zero, so we are done here. + return +end + +% In case we haven't evaluated fMinus in the previous section. +if isempty(fMinus) + fMinus = fMinusFunc(tMinus, yMinus, p); +end + +% Compute sigma/dt using chain rule. +sigmaDtPartial = sigmaDtPartialFunc(tMinus, yMinus, p, []); +sigmaDyPartialFMinus = sigmaDyPartialFunc(tMinus, yMinus, p, fMinus); +sigmaDtTotal = sigmaDtPartial + sigmaDyPartialFMinus; + +% Check that sigma/dt is not too close to zero. +sigmaDtThreshold = 10*eps(tMinus); +if sigmaDtTotal < sigmaDtThreshold + throw(switchingFunctionDerivativeZeroException(sigmaDtTotal, sigmaDtThreshold)); +end + +% Scale smaller vector in outer product by sigma/dt for efficiency +if dimy <= nDir + switchDiscontinuity = switchDiscontinuity./sigmaDtTotal; +else + switchCoeffs = switchCoeffs./sigmaDtTotal; +end + +update = update + switchDiscontinuity * switchCoeffs; +end + +%% Exceptions +function e = switchingFunctionDerivativeZeroException(dt, thresh) +id = 'IFDIFF:Sensitvity:UpdateSwitchingFunctionDerivativeZero'; +msg = [ ... + 'Unable to compute sensitivity update, ', ... + 'because total derivative of switching function w.r.t. time is close to zero: dt=%.10g<%.10g']; +e = MException(id, msg, dt, thresh); +end + diff --git a/toolbox/internal/_sensNew/finiteDifference.m b/toolbox/internal/_sensNew/finiteDifference.m new file mode 100644 index 0000000..5c706ad --- /dev/null +++ b/toolbox/internal/_sensNew/finiteDifference.m @@ -0,0 +1,39 @@ +function df = finiteDifference(f, x, h, v) +fx = f(x); +dimx = length(x); +dimf = length(fx); + +fulljac = isempty(v); +if fulljac + % Full jacobian + nd = dimx; + xh = x; +else + % Directional derivatives + nd = size(v, 2); + v = x + v*h; +end +df = zeros(dimf, nd); + +for i=1:nd + % Uniform step or different for each component/direction? + if isscalar(h) + hi = h; + else + hi = h(i); + end + if fulljac + % No directions given, so assume unit vectors + xh(i) = x(i) + hi; + else + xh = v(:, i); + end + % Compute forward finite difference + df(:, i) = (f(xh) - fx) ./ hi; + + % Restore original vector if only one component was disturbed. + if fulljac + xh(i) = x(i); + end +end +end diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m new file mode 100644 index 0000000..c7e1c42 --- /dev/null +++ b/toolbox/internal/_sensNew/testSensNew.m @@ -0,0 +1,49 @@ +%% Setup +% Canonical Example +rhs = @canonicalExampleRHS; +tspan = [0 20]; +initialvalues = [1; 0]; +parameters = 5.437; + +integrator = @ode45; +opts = odeset('AbsTol', 1e-8, 'RelTol', 1e-6); + +%% Preprocess +datahandle = prepareDatahandleForIntegration(rhs, 'integrator', integrator, 'options', opts); + +%% Solve +sol = solveODE(datahandle, tspan, initialvalues, parameters); +sw = sol.switches; + +%% Sensitivity +dirY = []; +dirP = []; +nDirY = length(initialvalues); +nDirP = length(parameters); +t = linspace(tspan(1), tspan(2), 1000); +sens = IFDIFFSensitivity(datahandle, sol, dirY, dirP); +sens = sens.eval(t); + +%% Plot +y = []; +tidx = 1; +for i=1:length(sw)+1 + if i < length(sw)+1 + tidxnew = tidx + find(t(tidx:end) >= sw(i), 1) - 1; + ti = t(tidx:tidxnew-1); + else + ti = t(tidx:end); + end + yi = reshape(deval(sens.GySol{i}, ti), length(initialvalues), nDirY + nDirP, []); + y = cat(3, y, yi); + tidx = tidxnew; +end + +figure; +tiledlayout(size(y, 1), size(y, 2)); +for i=1:size(y, 1) + for j=1:size(y, 2) + nexttile + plot(t, squeeze(y(i, j, :))); + end +end diff --git a/toolbox/internal/_sensNew/vdeRhs.m b/toolbox/internal/_sensNew/vdeRhs.m new file mode 100644 index 0000000..675a441 --- /dev/null +++ b/toolbox/internal/_sensNew/vdeRhs.m @@ -0,0 +1,18 @@ +function dG = vdeRhs(t, G, sol, p, nDirY, fDyPartial, fDpPartial) +y = deval(sol, t); +dimy = length(y); + +matrixG = reshape(G, dimy, []); +nDir = size(matrixG, 2); +nDirP = nDir - nDirY; + +% State propagation applies to both sensitivities w.r.t. initial values and parameters. +matrixDG = fDyPartial(t, y, p, matrixG); + +% Add source term for parameter sensitivities. +if nDirP > 0 + matrixDG(:, nDirY+1:end) = matrixDG(:, nDirY+1:end) + fDpPartial(t, y, p); +end + +dG = matrixDG(:); +end From 6742c6714bbf3e374ba53a36c2a5383a45b80480 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Tue, 26 May 2026 09:33:06 +0200 Subject: [PATCH 04/24] Fix incorrect comment in sensitivity update function --- toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m b/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m index 44482db..367dcb4 100644 --- a/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m +++ b/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m @@ -17,7 +17,7 @@ fMinus = []; end -% Compute: f_m - f_p - jump_t - jump_y*f_m +% Compute: f_p - f_m - jump_t - jump_y*f_m % Also apply updates: s += jump_y*s; for parameters additionally do s += jump_p*dir_p switchDiscontinuity = zeros(dimy, 1); if ~isempty(fPlusFunc) From 938cd95d2faaee2b7e288c45e02c6913c5833aaf Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Tue, 26 May 2026 09:33:53 +0200 Subject: [PATCH 05/24] Simplify VDE RHS interface --- .../_sensNew/@IFDIFFSensitivity/solveVde.m | 2 +- toolbox/internal/_sensNew/vdeRhs.m | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m index b55343c..d7e1b16 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m @@ -11,7 +11,7 @@ fDpPartial = @(t, y, p) finiteDifference(@(x) rhs(t, y, x), p, h, initialDirP); end -rhsVde = @(t, G) vdeRhs(t, G, this.solution, this.parameters, nDirY, fDyPartial, fDpPartial); +rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, fDyPartial, fDpPartial); initialValues = initialValues(:); sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); end diff --git a/toolbox/internal/_sensNew/vdeRhs.m b/toolbox/internal/_sensNew/vdeRhs.m index 675a441..e3c7d52 100644 --- a/toolbox/internal/_sensNew/vdeRhs.m +++ b/toolbox/internal/_sensNew/vdeRhs.m @@ -1,18 +1,20 @@ -function dG = vdeRhs(t, G, sol, p, nDirY, fDyPartial, fDpPartial) -y = deval(sol, t); +function dt = vdeRhs(t, sens, p, solNominalTrajectory, nDirY, fDyPartialFunc, fDpPartialFunc) +y = deval(solNominalTrajectory, t); dimy = length(y); -matrixG = reshape(G, dimy, []); -nDir = size(matrixG, 2); +sensMatrix = reshape(sens, dimy, []); +% Separate columns into initial value and parameter sensitivities. +nDir = size(sensMatrix, 2); nDirP = nDir - nDirY; % State propagation applies to both sensitivities w.r.t. initial values and parameters. -matrixDG = fDyPartial(t, y, p, matrixG); +sensMatrix = fDyPartialFunc(t, y, p, sensMatrix); % Add source term for parameter sensitivities. if nDirP > 0 - matrixDG(:, nDirY+1:end) = matrixDG(:, nDirY+1:end) + fDpPartial(t, y, p); + sensMatrix(:, nDirY+1:end) = sensMatrix(:, nDirY+1:end) + fDpPartialFunc(t, y, p); end -dG = matrixDG(:); +% Flatten output in column-major order. +dt = sensMatrix(:); end From 582ee8ec57f014553bdc6abaaaa5d322cf514421 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Mon, 1 Jun 2026 12:36:03 +0200 Subject: [PATCH 06/24] Add WIP class diagram for sensitivities --- docs/dev/sensitivity.mmd | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docs/dev/sensitivity.mmd diff --git a/docs/dev/sensitivity.mmd b/docs/dev/sensitivity.mmd new file mode 100644 index 0000000..e8f9a69 --- /dev/null +++ b/docs/dev/sensitivity.mmd @@ -0,0 +1,49 @@ +classDiagram + Sensitivity o-- Solution : Describes switching behavior and nominal trajectory + Sensitivity ..> Integrator : Calls to solve VDE (or ODE with disturbed inputs) + Sensitivity ..> Derivative : Calls to compute switch updates and VDE RHS + Integrator ..> Solution : Computes + Derivative <|.. FiniteDifference : Implements + class Sensitivity{ + +Solution nominal_trajectory + +Integrator integrator + +List~float~ switching_timepoints + +function rhs + +List~function~ switching_functions + +List~function~ jump_functions + +List~Derivatives~ derivative_rhs_submodels + +List~Derivative~ derivative_switching_functions + +List~Derivative~ derivative_jump_functions + +List~int~ initial_value_indices_for_which_to_compute + +List~int~ parameter_indices_for_which_to_compute + +float initial_time + +Matrix~float~ initial_value_sensitivity_initial_value + +Matrix~float~ parameter_sensitivity_initial_value + + +evaluate(List~float~ timepoints) List~Vector~float~~ sensitivity_at_timepoints + +get_dense_representation(List~float~ timepoints, List~Vector~float~~ sensitivity_at_timepoints) Solution + } + class Solution{ + +List~float~ timepoints + +List~Vector~float~~ solution_at_timepoints + +evaluate_dense(List~float~ timepoints) List~Vector~float~~ solution_at_timepoints + } + class Integrator{ + +function rhs + +float initial_time + +Vector~float~ initial_value + +Struct options + +solve(List~float~ timepoints) Solution + } + class Derivative{ + <> + +function f + +fdt(float t, Vector~float~ y, Vector~float~ p, float direction) Vector~float~ + +fdy(float t, Vector~float~ y, Vector~float~ p, Matrix~float~ direction) Matrix~float~ + +fdp(float t, Vector~float~ y, Vector~float~ p, Matrix~float~ direction) Matrix~float~ + } + + class FiniteDifference{ + +float step_size + +get_step_size(t, y, p) Vector~float~ + } From 2abc4b08cf4268751e3a40f6b07a8693fde30ce6 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Tue, 9 Jun 2026 17:51:32 +0200 Subject: [PATCH 07/24] WIP: Cleanup new sensitivity implementation --- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 137 ++++++++++-------- .../_sensNew/@IFDIFFSensitivity/solveVde.m | 17 --- ...ate.m => computeSensitivitySwitchUpdate.m} | 54 +++---- toolbox/internal/_sensNew/testSensNew.m | 24 ++- 4 files changed, 124 insertions(+), 108 deletions(-) delete mode 100644 toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m rename toolbox/internal/_sensNew/{applySensitivitySwitchUpdate.m => computeSensitivitySwitchUpdate.m} (53%) diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 5eebcab..3bdd71b 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -5,12 +5,6 @@ properties datahandle solution - Uy - Up - UyAccumulated - UpAccumulated - GySol = {} - GpSol parameters tspan switches @@ -19,8 +13,6 @@ switchesLeftY dimy dimp - fdStep - modelBoundaries integrator integratorOptions dirY @@ -43,7 +35,6 @@ this.tspan = data.SWP_detection.tspan; this.switches = sort(sol.switches); - this.modelBoundaries = [this.tspan(1), this.switches, this.tspan(end)]; [isSwitchInSol, switchesIdx] = ismember(this.switches, sol.x); if ~all(isSwitchInSol) @@ -55,11 +46,10 @@ this.switchesLeft = this.switches; this.switchesLeftY = this.switchesY; + % Use left limit of switch if there was a jump. this.switchesLeft(sol.jumps) = sol.x(switchesIdx(sol.jumps) - 1); this.switchesLeftY(:, sol.jumps) = sol.y(:, switchesIdx(sol.jumps) - 1); - this.fdStep = generateFDstep(this.dimy, this.dimp); - this.integrator = data.integratorSettings.numericIntegrator; this.integratorOptions = data.integratorSettings.options; @@ -73,7 +63,66 @@ this.dirP = dirP; end - function this = eval(this, timepoints) + function sol = solveVde(this, idxModel, tspan, initialValues, nDirY) + rhs = getRhsFromModelNum(this.datahandle, idxModel); + rhs = @(t, y, p) rhs(this.datahandle, t, y, p); + + h = 1e-6; % TODO: temporarily hard-coded + fDyPartial = @(t, y, p, v) finiteDifference(@(x) rhs(t, x, p), y, h, v); + nDirP = size(initialValues, 2) - nDirY; + if nDirP > 0 + fDpPartial = @(t, y, p) finiteDifference(@(x) rhs(t, y, x), p, h, this.dirP); + else + fDpPartial = []; + end + + rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, fDyPartial, fDpPartial); + initialValues = initialValues(:); + sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); + end + + function [sens, fPlus] = applySensitivitySwitchUpdate(this, sens, idxModel, fMinus) + tMinus = this.switchesLeft(idxModel); + tPlus = this.switches(idxModel); + yMinus = this.switchesLeftY(:, idxModel); + yPlus = this.switchesY(:, idxModel); + + % TODO: Fix ugly workaround after datahandle refactor. + % If the submodel is not exported as a separate function and instead relies on the datahandle, + % then we have to evaluate fMinus here, so that the signature is set correctly for fPlus. + if makeConfig().removeCtrlifForSensComputation + fMinusEval = fMinus(this.datahandle, tMinus, yMinus, this.parameters); + fMinus = @(~, ~, ~, ~) fMinusEval; + end + fPlus = getRhsFromModelNum(this.datahandle, idxModel + 1); + + % Setup derivatives. + sigma = this.switchingFunctions{idxModel}; + jump = this.jumpFunctions{idxModel}; + h = 1e-6; % TODO: temporarily hard-coded + sigmat = @(t, y, p, v) finiteDifference(@(x) sigma([], x, y, p), t, h, v); + sigmay = @(t, y, p, v) finiteDifference(@(x) sigma([], t, x, p), y, h, v); + sigmap = @(t, y, p, v) finiteDifference(@(x) sigma([], t, y, x), p, h, v); + if isempty(jump) + jumpt = []; + jumpy = []; + jumpp = []; + else + jumpt = @(t, y, p, v) finiteDifference(@(x) jump([], x, y, p), t, h, v); + jumpy = @(t, y, p, v) finiteDifference(@(x) jump([], t, x, p), y, h, v); + jumpp = @(t, y, p, v) finiteDifference(@(x) jump([], t, y, x), p, h, v); + end + + sens = computeSensitivitySwitchUpdate( ... + sens, this.dirP, ... + tMinus, tPlus, yMinus, yPlus, this.parameters, ... + @(t, y, p) fMinus(this.datahandle, t, y, p), @(t, y, p) fPlus(this.datahandle, t, y, p), ... + sigmat, sigmay, sigmap, ... + jumpt, jumpy, jumpp); + end + + function sensSol = eval(this, timepoints) + % Ensure timepoints are strictly increasing. [t, ~, idxTimepointsUndoSort] = unique(timepoints); if t(1) < this.tspan(1) || t(end) > this.tspan(end) @@ -82,57 +131,31 @@ 'the solution interval of the IVP.']); end + % TODO: May cache solution from previous runs for the same parameters. + % For now, always start solving from the first model. idxModelStart = 1; - % Find the switch, that would come after the last evaluation timepoint - idxModelEnd = find(t(end) <= this.modelBoundaries, 1) - 1; + % Determine the model of the last evaluation timepoint. + idxModelEnd = find(t(end) <= [this.switches, this.tspan(end)], 1); - tstart = this.tspan(1); - sens = [this.dirY, zeros(this.dimy, size(this.dirP, 2))]; + tModelStart = this.tspan(1); + sensInitialValue = [this.dirY, zeros(this.dimy, size(this.dirP, 2))]; nDirY = size(this.dirY, 2); - if idxModelEnd > idxModelStart - fMinus = getRhsFromModelNum(this.datahandle, idxModelStart); - end + + % Integrate each submodel until switch and apply update at the end. for idxModel=idxModelStart:idxModelEnd-1 - tend = this.switchesLeft(idxModel); - sol = this.solveVde(idxModel, [tstart, tend], sens, nDirY, this.dirP); - tstart = this.switches(idxModel); - this.GySol{idxModel} = sol; - - sens = reshape(sol.y(:, end), this.dimy, []); - - % Update (not on last iteration) - yMinus = this.switchesLeftY(:, idxModel); - yPlus = this.switchesY(:, idxModel); - fPlus = getRhsFromModelNum(this.datahandle, idxModel + 1); - sigma = this.switchingFunctions{idxModel}; - jump = this.jumpFunctions{idxModel}; - h = 1e-6; - sigmat = @(t, y, p, v) finiteDifference(@(x) sigma([], x, y, p), t, h, v); - sigmay = @(t, y, p, v) finiteDifference(@(x) sigma([], t, x, p), y, h, v); - sigmap = @(t, y, p, v) finiteDifference(@(x) sigma([], t, y, x), p, h, v); - if isempty(jump) - jumpt = []; - jumpy = []; - jumpp = []; - else - jumpt = @(t, y, p, v) finiteDifference(@(x) jump([], x, y, p), t, h, v); - jumpy = @(t, y, p, v) finiteDifference(@(x) jump([], t, x, p), y, h, v); - jumpp = @(t, y, p, v) finiteDifference(@(x) jump([], t, y, x), p, h, v); + tModelEnd = this.switchesLeft(idxModel); + sensSol(idxModel) = this.solveVde(idxModel, [tModelStart, tModelEnd], sensInitialValue, nDirY); %#ok + tModelStart = this.switches(idxModel); + % Update initial value for next VDE at switch. + sensInitialValue = reshape(sensSol(idxModel).y(:, end), this.dimy, []); + if idxModel == idxModelStart + fMinus = getRhsFromModelNum(this.datahandle, idxModelStart); end - sens = applySensitivitySwitchUpdate( ... - sens, this.dirP, size(this.dirY, 2), ... - tend, tstart, yMinus, yPlus, this.parameters, ... - @(t,y,p) fMinus(this.datahandle,t,y,p), @(t,y,p) fPlus(this.datahandle,t,y,p), ... - sigmat, sigmay, sigmap, ... - jumpt, jumpy, jumpp); - fMinus = fPlus; + [sensInitialValue, fMinus] = this.applySensitivitySwitchUpdate(sensInitialValue, idxModel, fMinus); end - idxModel = idxModel + 1; - tend = t(end); - sol = this.solveVde(idxModel, [tstart, tend], sens, nDirY, this.dirP); - this.GySol{idxModel} = sol; + % No more switches left, so solve until the end. + tModelEnd = t(end); + sensSol(idxModelEnd) = this.solveVde(idxModelEnd, [tModelStart, tModelEnd], sensInitialValue, nDirY); end - - sol = solveVde(this, idxModel, tspan, initialValues, nDirY, initialDirP) end end diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m deleted file mode 100644 index d7e1b16..0000000 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/solveVde.m +++ /dev/null @@ -1,17 +0,0 @@ -function sol = solveVde(this, idxModel, tspan, initialValues, nDirY, initialDirP) -rhs = getRhsFromModelNum(this.datahandle, idxModel); -rhs = @(t, y, p) rhs(this.datahandle, t, y, p); - - -h = 1e-6; -fDyPartial = @(t, y, p, v) finiteDifference(@(x) rhs(t, x, p), y, h, v); -if isempty(initialDirP) - fDpPartial = []; -else - fDpPartial = @(t, y, p) finiteDifference(@(x) rhs(t, y, x), p, h, initialDirP); -end - -rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, fDyPartial, fDpPartial); -initialValues = initialValues(:); -sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); -end diff --git a/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m b/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m similarity index 53% rename from toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m rename to toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m index 367dcb4..9decd0b 100644 --- a/toolbox/internal/_sensNew/applySensitivitySwitchUpdate.m +++ b/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m @@ -1,14 +1,15 @@ -function update = applySensitivitySwitchUpdate( ... - sens, pInitialDir, nDirY, ... +function sens = computeSensitivitySwitchUpdate( ... + sens, dirP, ... tMinus, tPlus, yMinus, yPlus, p, ... fMinusFunc, fPlusFunc, ... sigmaDtPartialFunc, sigmaDyPartialFunc, sigmaDpPartialFunc, ... jumpDtPartialFunc, jumpDyPartialFunc, jumpDpPartialFunc) -update = sens; -[dimy, nDir] = size(sens); % Determine which columns contain parameter sensitivities and which initial value sensitivities. -nDirP = nDir - nDirY; +% Assumption: Initial value sensitivities come first, then parameter sensitivities. +[dim, nDir] = size(sens); +nDirP = size(dirP, 2); +nDirY = nDir - nDirP; hasParameter = nDirP > 0; if ~isempty(fPlusFunc) || ~isempty(jumpDyPartialFunc) @@ -17,42 +18,43 @@ fMinus = []; end -% Compute: f_p - f_m - jump_t - jump_y*f_m -% Also apply updates: s += jump_y*s; for parameters additionally do s += jump_p*dir_p -switchDiscontinuity = zeros(dimy, 1); +% Compute derivative of solution wrt switching time: f_p - f_m - jump_t - jump_y*f_m +% Also apply state jump updates: s += jump_y*s; for parameters additionally do s += jump_p*dir_p +derivativeSolutionWrtSwitchingTime = zeros(dim, 1); if ~isempty(fPlusFunc) fPlus = fPlusFunc(tPlus, yPlus, p); - switchDiscontinuity = switchDiscontinuity + fPlus - fMinus; + derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime + fPlus - fMinus; end if ~isempty(jumpDtPartialFunc) - switchDiscontinuity = switchDiscontinuity - jumpDtPartialFunc(tMinus, yMinus, p, []); + derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime - jumpDtPartialFunc(tMinus, yMinus, p, []); end if ~isempty(jumpDyPartialFunc) % Evaluate jump_y in direction of sens and fMinus in one call for efficiency. % Last column belongs to fMinus. jumpDyPartial = jumpDyPartialFunc(tMinus, yMinus, p, [sens, fMinus]); - update = update + jumpDyPartial(:, 1:end-1); - switchDiscontinuity = switchDiscontinuity - jumpDyPartial(:, end); + sens = sens + jumpDyPartial(:, 1:end-1); + derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime - jumpDyPartial(:, end); end if hasParameter && ~isempty(jumpDpPartialFunc) % Apply only to parameter sensitivities. - update(:, nDirY+1:end) = update(:, nDirY+1:end) + jumpDpPartialFunc(tMinus, yMinus, p, pInitialDir); + sens(:, nDirY+1:end) = sens(:, nDirY+1:end) + jumpDpPartialFunc(tMinus, yMinus, p, dirP); end -if all(switchDiscontinuity == 0) +if all(derivativeSolutionWrtSwitchingTime == 0) % Remaining outer product term would be zero, so we are done here. return end -% Compute: sigma_y*s + sigma_p*dir_p -switchCoeffs = zeros(1, nDir); +% Compute derivative of switching time wrt initial value and parameter: sigma_y*s + sigma_p*dir_p +derivativeSwitchingTimeWrtParams = zeros(1, nDir); if ~isempty(sigmaDyPartialFunc) - switchCoeffs = switchCoeffs + sigmaDyPartialFunc(tMinus, yMinus, p, sens); + derivativeSwitchingTimeWrtParams = derivativeSwitchingTimeWrtParams + sigmaDyPartialFunc(tMinus, yMinus, p, sens); end if hasParameter && ~isempty(sigmaDpPartialFunc) % Apply only to parameter sensitivity components - switchCoeffs(nDirY+1:end) = switchCoeffs(nDirY+1:end) + sigmaDpPartialFunc(tMinus, yMinus, p, pInitialDir); + derivativeSwitchingTimeWrtParams(nDirY+1:end) = derivativeSwitchingTimeWrtParams(nDirY+1:end) ... + + sigmaDpPartialFunc(tMinus, yMinus, p, dirP); end -if all(switchCoeffs == 0) +if all(derivativeSwitchingTimeWrtParams == 0) % Remaining outer product term would be zero, so we are done here. return end @@ -64,8 +66,8 @@ % Compute sigma/dt using chain rule. sigmaDtPartial = sigmaDtPartialFunc(tMinus, yMinus, p, []); -sigmaDyPartialFMinus = sigmaDyPartialFunc(tMinus, yMinus, p, fMinus); -sigmaDtTotal = sigmaDtPartial + sigmaDyPartialFMinus; +sigmaDyPartialFminus = sigmaDyPartialFunc(tMinus, yMinus, p, fMinus); +sigmaDtTotal = sigmaDtPartial + sigmaDyPartialFminus; % Check that sigma/dt is not too close to zero. sigmaDtThreshold = 10*eps(tMinus); @@ -74,15 +76,16 @@ end % Scale smaller vector in outer product by sigma/dt for efficiency -if dimy <= nDir - switchDiscontinuity = switchDiscontinuity./sigmaDtTotal; +if dim <= nDir + derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime./sigmaDtTotal; else - switchCoeffs = switchCoeffs./sigmaDtTotal; + derivativeSwitchingTimeWrtParams = derivativeSwitchingTimeWrtParams./sigmaDtTotal; end -update = update + switchDiscontinuity * switchCoeffs; +sens = sens + derivativeSolutionWrtSwitchingTime * derivativeSwitchingTimeWrtParams; end + %% Exceptions function e = switchingFunctionDerivativeZeroException(dt, thresh) id = 'IFDIFF:Sensitvity:UpdateSwitchingFunctionDerivativeZero'; @@ -91,4 +94,3 @@ 'because total derivative of switching function w.r.t. time is close to zero: dt=%.10g<%.10g']; e = MException(id, msg, dt, thresh); end - diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m index c7e1c42..c392c51 100644 --- a/toolbox/internal/_sensNew/testSensNew.m +++ b/toolbox/internal/_sensNew/testSensNew.m @@ -20,7 +20,8 @@ dirP = []; nDirY = length(initialvalues); nDirP = length(parameters); -t = linspace(tspan(1), tspan(2), 1000); +%t = linspace(tspan(1), tspan(2), 1000); +t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); sens = IFDIFFSensitivity(datahandle, sol, dirY, dirP); sens = sens.eval(t); @@ -34,16 +35,23 @@ else ti = t(tidx:end); end - yi = reshape(deval(sens.GySol{i}, ti), length(initialvalues), nDirY + nDirP, []); + yi = reshape(deval(sens(i), ti), length(initialvalues), nDirY + nDirP, []); y = cat(3, y, yi); tidx = tidxnew; end -figure; -tiledlayout(size(y, 1), size(y, 2)); -for i=1:size(y, 1) - for j=1:size(y, 2) - nexttile - plot(t, squeeze(y(i, j, :))); +nPrev = 0; +for nDir=[nDirY, nDirP] + figure; + axs = []; + tiledlayout(size(y, 1), nDir); + for i=1:size(y, 1) + for j=1:nDir + axs(i,j) = nexttile; %#ok + plot(t, squeeze(y(i, nPrev + j, :))); + end end + ylim tight + linkaxes(axs) + nPrev = nDir; end From ff438a3865f17cbce3a64718c20c3bbb0705601f Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 10 Jun 2026 10:12:37 +0200 Subject: [PATCH 08/24] Return sensitivity at timepoints via piecewise sol evaluation --- .../canonicalExampleAnalyticSolution.m | 33 +------------------ .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 10 ++++-- toolbox/internal/_sensNew/evalPiecewiseFunc.m | 30 +++++++++++++++++ toolbox/internal/_sensNew/testSensNew.m | 22 +++++++++---- 4 files changed, 55 insertions(+), 40 deletions(-) create mode 100644 toolbox/internal/_sensNew/evalPiecewiseFunc.m diff --git a/toolbox/examples/canonicalExample/canonicalExampleAnalyticSolution.m b/toolbox/examples/canonicalExample/canonicalExampleAnalyticSolution.m index 3c0ceee..7723755 100644 --- a/toolbox/examples/canonicalExample/canonicalExampleAnalyticSolution.m +++ b/toolbox/examples/canonicalExample/canonicalExampleAnalyticSolution.m @@ -123,36 +123,5 @@ yFull{idxModel} = @(t) [y{1, idxModel}(t); y{2, idxModel}(t)]; end -funcSolPiecewise = @(t) evalPiecewise(t, yFull, length(y0), tSwitch); -end - -function y = evalPiecewise(t, solPiece, dimy, sw) -% Make sure eval points and switching times are sorted in ascending order. -[t, tSortIdx] = sort(t); -sw = sort(sw); -y = zeros(dimy, length(t)); - -done = false; -idxModelStart = 1; -for idxSw=1:length(sw) - % Since eval points and switching times are sorted, we look for the first eval point that lies after the next switch. - idxModelEnd = (idxModelStart - 1) + find(t(idxModelStart:end) >= sw(idxSw), 1); - % If no such point exists, then we stay in the same model until the end. - if isempty(idxModelEnd) - y(:, idxModelStart:end) = solPiece{idxSw}(t(idxModelStart:end)); - done = true; - break - end - % Otherwise, evaluate points before switch in the current model and update model for next iteration. - y(:, idxModelStart:idxModelEnd-1) = solPiece{idxSw}(t(idxModelStart:idxModelEnd-1)); - idxModelStart = idxModelEnd; -end - -% If we actually reach the last model or stay in first model, then we have to evaluate the remaining points in that model. -if ~done - y(:, idxModelStart:end) = solPiece{end}(t(idxModelStart:end)); -end - -% Reverse the sorting -y(:, tSortIdx) = y(:, 1:end); +funcSolPiecewise = @(t) evalPiecewiseFunc(t, yFull, length(y0), tSwitch); end diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 3bdd71b..55e5212 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -121,7 +121,7 @@ jumpt, jumpy, jumpp); end - function sensSol = eval(this, timepoints) + function [sens, sensSol] = eval(this, timepoints) % Ensure timepoints are strictly increasing. [t, ~, idxTimepointsUndoSort] = unique(timepoints); @@ -140,7 +140,7 @@ tModelStart = this.tspan(1); sensInitialValue = [this.dirY, zeros(this.dimy, size(this.dirP, 2))]; nDirY = size(this.dirY, 2); - + % Integrate each submodel until switch and apply update at the end. for idxModel=idxModelStart:idxModelEnd-1 tModelEnd = this.switchesLeft(idxModel); @@ -156,6 +156,12 @@ % No more switches left, so solve until the end. tModelEnd = t(end); sensSol(idxModelEnd) = this.solveVde(idxModelEnd, [tModelStart, tModelEnd], sensInitialValue, nDirY); + + % Return sensitivity at requested timepoints + piecewiseFunc = arrayfun(@(sol) @(t) deval(sol, t), sensSol, 'UniformOutput', false); + sensUnique = evalPiecewiseFunc(t, piecewiseFunc, numel(sensInitialValue), this.switches); + sensUnique = reshape(sensUnique, this.dimy, size(sensInitialValue, 2), []); + sens = sensUnique(:, :, idxTimepointsUndoSort); end end end diff --git a/toolbox/internal/_sensNew/evalPiecewiseFunc.m b/toolbox/internal/_sensNew/evalPiecewiseFunc.m new file mode 100644 index 0000000..caf3ea3 --- /dev/null +++ b/toolbox/internal/_sensNew/evalPiecewiseFunc.m @@ -0,0 +1,30 @@ +function y = evalPiecewiseFunc(t, piecewiseFunc, dimy, switches) +% Make sure eval points and switching times are sorted in ascending order. +[t, ~, tUndoSortIdx] = unique(t); +switches = unique(switches); +y = zeros(dimy, length(t)); + +done = false; +idxModelStart = 1; +for idxSw=1:length(switches) + % Since eval points and switching times are sorted, we look for the first eval point that lies after the next switch. + idxModelEnd = (idxModelStart - 1) + find(t(idxModelStart:end) >= switches(idxSw), 1); + % If no such point exists, then we stay in the same model until the end. + if isempty(idxModelEnd) + y(:, idxModelStart:end) = piecewiseFunc{idxSw}(t(idxModelStart:end)); + done = true; + break + end + % Otherwise, evaluate points before switch in the current model and update model for next iteration. + y(:, idxModelStart:idxModelEnd-1) = piecewiseFunc{idxSw}(t(idxModelStart:idxModelEnd-1)); + idxModelStart = idxModelEnd; +end + +% If we actually reach the last model or stay in first model, then we have to evaluate the remaining points in that model. +if ~done + y(:, idxModelStart:end) = piecewiseFunc{end}(t(idxModelStart:end)); +end + +% Reverse the sorting +y(:, tUndoSortIdx) = y(:, 1:end); +end diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m index c392c51..c20d0ca 100644 --- a/toolbox/internal/_sensNew/testSensNew.m +++ b/toolbox/internal/_sensNew/testSensNew.m @@ -21,11 +21,15 @@ nDirY = length(initialvalues); nDirP = length(parameters); %t = linspace(tspan(1), tspan(2), 1000); -t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); -sens = IFDIFFSensitivity(datahandle, sol, dirY, dirP); -sens = sens.eval(t); +%t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); +t = jumpLinspace(tspan(1), tspan(end), sol.switches, 1e5); +sensObj = IFDIFFSensitivity(datahandle, sol, dirY, dirP); +[sensT, sensSol] = sensObj.eval(t); -%% Plot +%% Plot directly +plotTiled(t, sensT, nDirY, nDirP) + +%% Plot via sol y = []; tidx = 1; for i=1:length(sw)+1 @@ -35,11 +39,15 @@ else ti = t(tidx:end); end - yi = reshape(deval(sens(i), ti), length(initialvalues), nDirY + nDirP, []); + yi = reshape(deval(sensSol(i), ti), length(initialvalues), nDirY + nDirP, []); y = cat(3, y, yi); tidx = tidxnew; end +plotTiled(t, y, nDirY, nDirP) + +%% Helper +function plotTiled(t, y, nDirY, nDirP) nPrev = 0; for nDir=[nDirY, nDirP] figure; @@ -47,11 +55,13 @@ tiledlayout(size(y, 1), nDir); for i=1:size(y, 1) for j=1:nDir - axs(i,j) = nexttile; %#ok + axs(i,j) = nexttile; %#ok plot(t, squeeze(y(i, nPrev + j, :))); + title(sprintf('G_{%d%d}', i, j)) end end ylim tight linkaxes(axs) nPrev = nDir; end +end From d2dc5bb28c37785a76760337c196b9a7015a4e99 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 10 Jun 2026 11:42:58 +0200 Subject: [PATCH 09/24] WIP: Implement new sensitivity into old interface and fix bugs --- toolbox/generateSensitivityFunction.m | 14 +++++++++++++ .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 21 ++++++++++++------- .../_sensNew/computeSensitivitySwitchUpdate.m | 11 +++++----- toolbox/internal/_sensNew/testSensNew.m | 20 +++++++++++++++--- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/toolbox/generateSensitivityFunction.m b/toolbox/generateSensitivityFunction.m index eda7b9c..47143ba 100644 --- a/toolbox/generateSensitivityFunction.m +++ b/toolbox/generateSensitivityFunction.m @@ -83,6 +83,20 @@ % INPUT: t_all - vector of timepoints at which you want to calculate the sensitivities % % OUTPUT: sensitivities - struct that contains the given timepoints, the calculated sensitivities and the intermediate G-matrices + + if method == methodCoded.VDE + sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, [], []); + sensT = sensObj.eval(t_all); + for i=1:size(sensT, 3) + if Gy_flag + sensitivities(i).Gy = sensT(:, 1:dim_y, i); + end + if Gp_flag + sensitivities(i).Gp = sensT(:, 1+dim_y*Gy_flag:end, i); + end + end + return + end [t_sort_unique, ~, unique_indices] = unique(t_all); diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 55e5212..8d1fa2b 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -22,7 +22,7 @@ end methods - function this = IFDIFFSensitivity(datahandle, sol, dirY, dirP) + function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP) this.datahandle = datahandle; this.solution = sol; data = datahandle.getData(); @@ -52,11 +52,18 @@ this.integrator = data.integratorSettings.numericIntegrator; this.integratorOptions = data.integratorSettings.options; - - if isempty(dirY) + + if ~calcGy && ~calcGp + error('IFDIFF:Sensitivity:NothingToCompute', 'Neither initial value nor parameter sensitivity was requested.') + end + if ~calcGy + dirY = []; + elseif isempty(dirY) dirY = eye(this.dimy); end - if isempty(dirP) + if ~calcGp + dirP = []; + elseif isempty(dirP) dirP = eye(this.dimp); end this.dirY = dirY; @@ -159,9 +166,9 @@ % Return sensitivity at requested timepoints piecewiseFunc = arrayfun(@(sol) @(t) deval(sol, t), sensSol, 'UniformOutput', false); - sensUnique = evalPiecewiseFunc(t, piecewiseFunc, numel(sensInitialValue), this.switches); - sensUnique = reshape(sensUnique, this.dimy, size(sensInitialValue, 2), []); - sens = sensUnique(:, :, idxTimepointsUndoSort); + sens = evalPiecewiseFunc(t, piecewiseFunc, numel(sensInitialValue), this.switches); + sens = reshape(sens, this.dimy, size(sensInitialValue, 2), []); + sens = sens(:, :, idxTimepointsUndoSort); end end end diff --git a/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m b/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m index 9decd0b..0c1076d 100644 --- a/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m +++ b/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m @@ -1,10 +1,11 @@ -function sens = computeSensitivitySwitchUpdate( ... +function update = computeSensitivitySwitchUpdate( ... sens, dirP, ... tMinus, tPlus, yMinus, yPlus, p, ... fMinusFunc, fPlusFunc, ... sigmaDtPartialFunc, sigmaDyPartialFunc, sigmaDpPartialFunc, ... jumpDtPartialFunc, jumpDyPartialFunc, jumpDpPartialFunc) +update = sens; % Determine which columns contain parameter sensitivities and which initial value sensitivities. % Assumption: Initial value sensitivities come first, then parameter sensitivities. [dim, nDir] = size(sens); @@ -32,12 +33,12 @@ % Evaluate jump_y in direction of sens and fMinus in one call for efficiency. % Last column belongs to fMinus. jumpDyPartial = jumpDyPartialFunc(tMinus, yMinus, p, [sens, fMinus]); - sens = sens + jumpDyPartial(:, 1:end-1); + update = update + jumpDyPartial(:, 1:end-1); derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime - jumpDyPartial(:, end); end if hasParameter && ~isempty(jumpDpPartialFunc) % Apply only to parameter sensitivities. - sens(:, nDirY+1:end) = sens(:, nDirY+1:end) + jumpDpPartialFunc(tMinus, yMinus, p, dirP); + update(:, nDirY+1:end) = update(:, nDirY+1:end) + jumpDpPartialFunc(tMinus, yMinus, p, dirP); end if all(derivativeSolutionWrtSwitchingTime == 0) % Remaining outer product term would be zero, so we are done here. @@ -71,7 +72,7 @@ % Check that sigma/dt is not too close to zero. sigmaDtThreshold = 10*eps(tMinus); -if sigmaDtTotal < sigmaDtThreshold +if abs(sigmaDtTotal) < sigmaDtThreshold throw(switchingFunctionDerivativeZeroException(sigmaDtTotal, sigmaDtThreshold)); end @@ -82,7 +83,7 @@ derivativeSwitchingTimeWrtParams = derivativeSwitchingTimeWrtParams./sigmaDtTotal; end -sens = sens + derivativeSolutionWrtSwitchingTime * derivativeSwitchingTimeWrtParams; +update = update + derivativeSolutionWrtSwitchingTime * derivativeSwitchingTimeWrtParams; end diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m index c20d0ca..360a1c7 100644 --- a/toolbox/internal/_sensNew/testSensNew.m +++ b/toolbox/internal/_sensNew/testSensNew.m @@ -17,13 +17,24 @@ %% Sensitivity dirY = []; +calcGy = true; +%dirY = [1, 0; 0, 1; 1, 1]'; +calcGp = false; dirP = []; -nDirY = length(initialvalues); -nDirP = length(parameters); +if calcGy && isempty(dirY) + nDirY = length(initialvalues); +else + nDirY = size(dirY, 2); +end +if calcGp && isempty(dirP) + nDirP = length(parameters); +else + nDirP = size(dirP, 2); +end %t = linspace(tspan(1), tspan(2), 1000); %t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); t = jumpLinspace(tspan(1), tspan(end), sol.switches, 1e5); -sensObj = IFDIFFSensitivity(datahandle, sol, dirY, dirP); +sensObj = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP); [sensT, sensSol] = sensObj.eval(t); %% Plot directly @@ -50,6 +61,9 @@ function plotTiled(t, y, nDirY, nDirP) nPrev = 0; for nDir=[nDirY, nDirP] + if nDir == 0 + continue + end figure; axs = []; tiledlayout(size(y, 1), nDir); From f0226122a752fbf006cfcded212edb07b97660c5 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 14 Jun 2026 17:16:33 +0200 Subject: [PATCH 10/24] Refactor finite difference computation with class --- toolbox/generateSensitivityFunction.m | 2 +- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 39 ++---- toolbox/internal/_sensNew/IFDIFFDerivative.m | 7 + .../IFDIFFDerivativeFiniteDifferences.m | 126 ++++++++++++++++++ .../_sensNew/computeSensitivitySwitchUpdate.m | 42 +++--- toolbox/internal/_sensNew/finiteDifference.m | 39 ------ toolbox/internal/_sensNew/vdeRhs.m | 6 +- 7 files changed, 171 insertions(+), 90 deletions(-) create mode 100644 toolbox/internal/_sensNew/IFDIFFDerivative.m create mode 100644 toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m delete mode 100644 toolbox/internal/_sensNew/finiteDifference.m diff --git a/toolbox/generateSensitivityFunction.m b/toolbox/generateSensitivityFunction.m index 47143ba..532c9d2 100644 --- a/toolbox/generateSensitivityFunction.m +++ b/toolbox/generateSensitivityFunction.m @@ -85,7 +85,7 @@ % OUTPUT: sensitivities - struct that contains the given timepoints, the calculated sensitivities and the intermediate G-matrices if method == methodCoded.VDE - sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, [], []); + sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, [], [], FDstep); sensT = sensObj.eval(t_all); for i=1:size(sensT, 3) if Gy_flag diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 8d1fa2b..68b59dc 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -19,10 +19,11 @@ dirP switchingFunctions jumpFunctions + fdStep end methods - function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP) + function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP, fdStep) this.datahandle = datahandle; this.solution = sol; data = datahandle.getData(); @@ -52,7 +53,7 @@ this.integrator = data.integratorSettings.numericIntegrator; this.integratorOptions = data.integratorSettings.options; - + if ~calcGy && ~calcGp error('IFDIFF:Sensitivity:NothingToCompute', 'Neither initial value nor parameter sensitivity was requested.') end @@ -68,22 +69,15 @@ end this.dirY = dirY; this.dirP = dirP; + + this.fdStep = fdStep; end function sol = solveVde(this, idxModel, tspan, initialValues, nDirY) rhs = getRhsFromModelNum(this.datahandle, idxModel); - rhs = @(t, y, p) rhs(this.datahandle, t, y, p); - - h = 1e-6; % TODO: temporarily hard-coded - fDyPartial = @(t, y, p, v) finiteDifference(@(x) rhs(t, x, p), y, h, v); - nDirP = size(initialValues, 2) - nDirY; - if nDirP > 0 - fDpPartial = @(t, y, p) finiteDifference(@(x) rhs(t, y, x), p, h, this.dirP); - else - fDpPartial = []; - end + df = IFDIFFDerivativeFiniteDifferences(this.datahandle, rhs, this.fdStep); - rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, fDyPartial, fDpPartial); + rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, df, this.dirP); initialValues = initialValues(:); sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); end @@ -106,26 +100,19 @@ % Setup derivatives. sigma = this.switchingFunctions{idxModel}; jump = this.jumpFunctions{idxModel}; - h = 1e-6; % TODO: temporarily hard-coded - sigmat = @(t, y, p, v) finiteDifference(@(x) sigma([], x, y, p), t, h, v); - sigmay = @(t, y, p, v) finiteDifference(@(x) sigma([], t, x, p), y, h, v); - sigmap = @(t, y, p, v) finiteDifference(@(x) sigma([], t, y, x), p, h, v); - if isempty(jump) - jumpt = []; - jumpy = []; - jumpp = []; + + dsigma = IFDIFFDerivativeFiniteDifferences([], sigma, this.fdStep); + if ~isempty(jump) + djump = IFDIFFDerivativeFiniteDifferences([], jump, this.fdStep); else - jumpt = @(t, y, p, v) finiteDifference(@(x) jump([], x, y, p), t, h, v); - jumpy = @(t, y, p, v) finiteDifference(@(x) jump([], t, x, p), y, h, v); - jumpp = @(t, y, p, v) finiteDifference(@(x) jump([], t, y, x), p, h, v); + djump = []; end sens = computeSensitivitySwitchUpdate( ... sens, this.dirP, ... tMinus, tPlus, yMinus, yPlus, this.parameters, ... @(t, y, p) fMinus(this.datahandle, t, y, p), @(t, y, p) fPlus(this.datahandle, t, y, p), ... - sigmat, sigmay, sigmap, ... - jumpt, jumpy, jumpp); + dsigma, djump); end function [sens, sensSol] = eval(this, timepoints) diff --git a/toolbox/internal/_sensNew/IFDIFFDerivative.m b/toolbox/internal/_sensNew/IFDIFFDerivative.m new file mode 100644 index 0000000..f1a8350 --- /dev/null +++ b/toolbox/internal/_sensNew/IFDIFFDerivative.m @@ -0,0 +1,7 @@ +classdef IFDIFFDerivative < handle + methods (Abstract, Access=public) + d = dt(this, t, y, p, v) + d = dy(this, t, y, p, v) + d = dp(this, t, y, p, v) + end +end diff --git a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m new file mode 100644 index 0000000..c9db43d --- /dev/null +++ b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m @@ -0,0 +1,126 @@ +classdef IFDIFFDerivativeFiniteDifferences < IFDIFFDerivative + %this = IFDIFFDERIVATIVEFINITEDIFFERENCES(datahandle, f, step) + % + %Compute derivatives w.r.t. t, y, p for functions generated by IFDIFF (i.e. rhs, switching, jump, submodel). + %First order forward finite differences are used for the computation. + % + %INPUT: + % datahandle - Provides signature for forced branching if function contains ctrlifs (only the case for rhs). + % struct + % + % f - Function whose derivative will be computed. Signature must be: out = f(datahandle, t, y, p). + % function_handle + % + % step - Step size information for the finite difference method. Should always come from a call to generateFDstep. + % struct + + properties (Access=public) + datahandle + f % out = f(datahandle, t, y, p) + step % from generateFDstep + end + methods (Access=public) + function this = IFDIFFDerivativeFiniteDifferences(datahandle, f, step) + if nargin == 0 + return + end + + this.datahandle = datahandle; + this.f = f; + this.step = step; + end + + %% Derivatives + % Note: Code for computing derivatives for different arguments (i.e. t,y,p) is deliberately duplicated here, + % because these functions will be called many times by the integrator when solving the VDE and we want to avoid + % performance loss due to overhead from anonymous functions. + function df = dt(this, t, y, p, v) + f0 = this.f(this.datahandle, t, y, p); + + dimf = length(f0); + nd = size(v, 2); + df = zeros(dimf, nd); + + normv = vecnorm(v, 2, 1); + idxNonzero = find(normv); + v = v(:, idxNonzero) ./ normv(idxNonzero); + + % Assume that h is a column vector which contains a step size for each component. + % To determine the step size for an arbitrary direction v compute the scalar product of h and v. + h = this.ht(t)' * v; + v = t + v.*h; + for i=1:size(v, 2) + fh = this.f(this.datahandle, v(:, i), y, p); + df(:, idxNonzero(i)) = (fh - f0) ./ h(i); + end + df(:, idxNonzero) = df(:, idxNonzero) .* normv(idxNonzero); + end + function df = dy(this, t, y, p, v) + f0 = this.f(this.datahandle, t, y, p); + + dimf = length(f0); + nd = size(v, 2); + df = zeros(dimf, nd); + + normv = vecnorm(v, 2, 1); + idxNonzero = find(normv); + v = v(:, idxNonzero) ./ normv(idxNonzero); + + % Assume that h is a column vector which contains a step size for each component. + % To determine the step size for an arbitrary direction v compute the scalar product of h and v. + h = this.hy(y)' * v; + v = y + v.*h; + for i=1:size(v, 2) + fh = this.f(this.datahandle, t, v(:, i), p); + df(:, idxNonzero(i)) = (fh - f0) ./ h(i); + end + df(:, idxNonzero) = df(:, idxNonzero) .* normv(idxNonzero); + end + function df = dp(this, t, y, p, v) + f0 = this.f(this.datahandle, t, y, p); + + dimf = length(f0); + nd = size(v, 2); + df = zeros(dimf, nd); + + normv = vecnorm(v, 2, 1); + idxNonzero = find(normv); + v = v(:, idxNonzero) ./ normv(idxNonzero); + + % Assume that h is a column vector which contains a step size for each component. + % To determine the step size for an arbitrary direction v compute the scalar product of h and v. + h = this.hp(p)' * v; + v = p + v.*h; + for i=1:size(v, 2) + fh = this.f(this.datahandle, t, y, v(:, i)); + df(:, idxNonzero(i)) = (fh - f0) ./ h(i); + end + df(:, idxNonzero) = df(:, idxNonzero) .* normv(idxNonzero); + end + end + + %% Step size + methods (Access=private) + function h = ht(this, t) + if this.step.t_rel + h = max(this.step.t_min, abs(t) .* this.step.t); + else + h = this.step.t; + end + end + function h = hy(this, y) + if this.step.y_rel + h = max(this.step.y_min, abs(y) .* this.step.y); + else + h = this.step.y; + end + end + function h = hp(this, p) + if this.step.p_rel + h = max(this.step.p_min, abs(p) .* this.step.p); + else + h = this.step.p; + end + end + end +end diff --git a/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m b/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m index 0c1076d..4b30652 100644 --- a/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m +++ b/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m @@ -2,8 +2,7 @@ sens, dirP, ... tMinus, tPlus, yMinus, yPlus, p, ... fMinusFunc, fPlusFunc, ... - sigmaDtPartialFunc, sigmaDyPartialFunc, sigmaDpPartialFunc, ... - jumpDtPartialFunc, jumpDyPartialFunc, jumpDpPartialFunc) + dsigma, djump) update = sens; % Determine which columns contain parameter sensitivities and which initial value sensitivities. @@ -13,7 +12,7 @@ nDirY = nDir - nDirP; hasParameter = nDirP > 0; -if ~isempty(fPlusFunc) || ~isempty(jumpDyPartialFunc) +if ~isempty(fPlusFunc) || ~isempty(djump) fMinus = fMinusFunc(tMinus, yMinus, p); else fMinus = []; @@ -26,20 +25,21 @@ fPlus = fPlusFunc(tPlus, yPlus, p); derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime + fPlus - fMinus; end -if ~isempty(jumpDtPartialFunc) - derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime - jumpDtPartialFunc(tMinus, yMinus, p, []); -end -if ~isempty(jumpDyPartialFunc) +if ~isempty(djump) + derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime - djump.dt(tMinus, yMinus, p, 1); + % Evaluate jump_y in direction of sens and fMinus in one call for efficiency. % Last column belongs to fMinus. - jumpDyPartial = jumpDyPartialFunc(tMinus, yMinus, p, [sens, fMinus]); + jumpDyPartial = djump.dy(tMinus, yMinus, p, [sens, fMinus]); update = update + jumpDyPartial(:, 1:end-1); derivativeSolutionWrtSwitchingTime = derivativeSolutionWrtSwitchingTime - jumpDyPartial(:, end); + + if hasParameter + % Apply only to parameter sensitivities. + update(:, nDirY+1:end) = update(:, nDirY+1:end) + djump.dp(tMinus, yMinus, p, dirP); + end end -if hasParameter && ~isempty(jumpDpPartialFunc) - % Apply only to parameter sensitivities. - update(:, nDirY+1:end) = update(:, nDirY+1:end) + jumpDpPartialFunc(tMinus, yMinus, p, dirP); -end + if all(derivativeSolutionWrtSwitchingTime == 0) % Remaining outer product term would be zero, so we are done here. return @@ -47,13 +47,13 @@ % Compute derivative of switching time wrt initial value and parameter: sigma_y*s + sigma_p*dir_p derivativeSwitchingTimeWrtParams = zeros(1, nDir); -if ~isempty(sigmaDyPartialFunc) - derivativeSwitchingTimeWrtParams = derivativeSwitchingTimeWrtParams + sigmaDyPartialFunc(tMinus, yMinus, p, sens); -end -if hasParameter && ~isempty(sigmaDpPartialFunc) - % Apply only to parameter sensitivity components - derivativeSwitchingTimeWrtParams(nDirY+1:end) = derivativeSwitchingTimeWrtParams(nDirY+1:end) ... - + sigmaDpPartialFunc(tMinus, yMinus, p, dirP); +if ~isempty(dsigma) + derivativeSwitchingTimeWrtParams = derivativeSwitchingTimeWrtParams + dsigma.dy(tMinus, yMinus, p, sens); + if hasParameter + % Apply only to parameter sensitivity components + derivativeSwitchingTimeWrtParams(nDirY+1:end) = derivativeSwitchingTimeWrtParams(nDirY+1:end) ... + + dsigma.dp(tMinus, yMinus, p, dirP); + end end if all(derivativeSwitchingTimeWrtParams == 0) % Remaining outer product term would be zero, so we are done here. @@ -66,8 +66,8 @@ end % Compute sigma/dt using chain rule. -sigmaDtPartial = sigmaDtPartialFunc(tMinus, yMinus, p, []); -sigmaDyPartialFminus = sigmaDyPartialFunc(tMinus, yMinus, p, fMinus); +sigmaDtPartial = dsigma.dt(tMinus, yMinus, p, 1); +sigmaDyPartialFminus = dsigma.dy(tMinus, yMinus, p, fMinus); sigmaDtTotal = sigmaDtPartial + sigmaDyPartialFminus; % Check that sigma/dt is not too close to zero. diff --git a/toolbox/internal/_sensNew/finiteDifference.m b/toolbox/internal/_sensNew/finiteDifference.m deleted file mode 100644 index 5c706ad..0000000 --- a/toolbox/internal/_sensNew/finiteDifference.m +++ /dev/null @@ -1,39 +0,0 @@ -function df = finiteDifference(f, x, h, v) -fx = f(x); -dimx = length(x); -dimf = length(fx); - -fulljac = isempty(v); -if fulljac - % Full jacobian - nd = dimx; - xh = x; -else - % Directional derivatives - nd = size(v, 2); - v = x + v*h; -end -df = zeros(dimf, nd); - -for i=1:nd - % Uniform step or different for each component/direction? - if isscalar(h) - hi = h; - else - hi = h(i); - end - if fulljac - % No directions given, so assume unit vectors - xh(i) = x(i) + hi; - else - xh = v(:, i); - end - % Compute forward finite difference - df(:, i) = (f(xh) - fx) ./ hi; - - % Restore original vector if only one component was disturbed. - if fulljac - xh(i) = x(i); - end -end -end diff --git a/toolbox/internal/_sensNew/vdeRhs.m b/toolbox/internal/_sensNew/vdeRhs.m index e3c7d52..2eab0c3 100644 --- a/toolbox/internal/_sensNew/vdeRhs.m +++ b/toolbox/internal/_sensNew/vdeRhs.m @@ -1,4 +1,4 @@ -function dt = vdeRhs(t, sens, p, solNominalTrajectory, nDirY, fDyPartialFunc, fDpPartialFunc) +function dt = vdeRhs(t, sens, p, solNominalTrajectory, nDirY, df, dirP) y = deval(solNominalTrajectory, t); dimy = length(y); @@ -8,11 +8,11 @@ nDirP = nDir - nDirY; % State propagation applies to both sensitivities w.r.t. initial values and parameters. -sensMatrix = fDyPartialFunc(t, y, p, sensMatrix); +sensMatrix = df.dy(t, y, p, sensMatrix); % Add source term for parameter sensitivities. if nDirP > 0 - sensMatrix(:, nDirY+1:end) = sensMatrix(:, nDirY+1:end) + fDpPartialFunc(t, y, p); + sensMatrix(:, nDirY+1:end) = sensMatrix(:, nDirY+1:end) + df.dp(t, y, p, dirP); end % Flatten output in column-major order. From 478fb9d555e93d6d67c1277e4502e153adaf2a9b Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 14 Jun 2026 17:19:13 +0200 Subject: [PATCH 11/24] Fix inverted logic for submodel export config flag in sens updates --- .../internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 68b59dc..e84a94f 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -91,7 +91,7 @@ % TODO: Fix ugly workaround after datahandle refactor. % If the submodel is not exported as a separate function and instead relies on the datahandle, % then we have to evaluate fMinus here, so that the signature is set correctly for fPlus. - if makeConfig().removeCtrlifForSensComputation + if ~makeConfig().removeCtrlifForSensComputation fMinusEval = fMinus(this.datahandle, tMinus, yMinus, this.parameters); fMinus = @(~, ~, ~, ~) fMinusEval; end From d11beb2f143b19fd07e0df60776eb56d7dda30bb Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Mon, 15 Jun 2026 12:15:29 +0200 Subject: [PATCH 12/24] Add direction argument for sensitivity in main interface for VDE method --- toolbox/generateSensitivityFunction.m | 30 ++++++++++++------- toolbox/internal/_sensNew/testSensNew.m | 27 +++++++++++++++-- .../compute_sensitivity_ENDfull_p.m | 4 +-- .../compute_sensitivity_ENDfull_y.m | 4 +-- 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/toolbox/generateSensitivityFunction.m b/toolbox/generateSensitivityFunction.m index 532c9d2..d40d757 100644 --- a/toolbox/generateSensitivityFunction.m +++ b/toolbox/generateSensitivityFunction.m @@ -21,8 +21,8 @@ % or VDE should be included in the output struct % 'method' - method that should be used to calculate the sensitivities (you can choose from END_full, % END_piecewise and VDE) - % 'directions_y' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. y0 if you use END_full - % 'directions_p' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. p if you use END_full + % 'directions_y' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. y0 if you use END_full or VDE + % 'directions_p' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. p if you use END_full or VDE % % OUTPUT: sensitivities_function - function that that can take a vector of timepoints and the struct FDstep with the stepsizes for END % as inputs and calculates the sensitivities at the given timepoints. @@ -41,10 +41,11 @@ method = olGetOption(varargin, 'method', 'VDE'); Gmatrices_intermediate_flag = olGetOption(varargin, 'Gmatrices_intermediate', false); Gy_flag = olGetOption(varargin, 'calcGy', true); - directions_y = olGetOption(varargin, 'directions_y', 0); + directions_y = olGetOption(varargin, 'directions_y', []); Gp_flag = olGetOption(varargin, 'calcGp', true); - directions_p = olGetOption(varargin, 'directions_p', 0); + directions_p = olGetOption(varargin, 'directions_p', []); save_intermediates = olGetOption(varargin, 'save_intermediates', true); + legacy = olGetOption(varargin, 'legacy', false); methodCoded.END_piecewise = 1; methodCoded.VDE = 2; @@ -84,15 +85,24 @@ % % OUTPUT: sensitivities - struct that contains the given timepoints, the calculated sensitivities and the intermediate G-matrices - if method == methodCoded.VDE - sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, [], [], FDstep); - sensT = sensObj.eval(t_all); - for i=1:size(sensT, 3) + if ~legacy && method == methodCoded.VDE + sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, directions_y, directions_p, FDstep); + sens = sensObj.eval(t_all); + if Gy_flag + ndirY = size(directions_y, 2); + if ndirY == 0; ndirY = dim_y; end + end + if Gp_flag + ndirP = size(directions_p, 2); + if ndirP == 0; ndirP = dim_p; end + end + for i=1:size(sens, 3) if Gy_flag - sensitivities(i).Gy = sensT(:, 1:dim_y, i); + sensitivities(i).Gy = sens(:, 1:ndirY, i); end if Gp_flag - sensitivities(i).Gp = sensT(:, 1+dim_y*Gy_flag:end, i); + % Parameter sensitivities are stored after initial value sensitivities (if there are any). + sensitivities(i).Gp = sens(:, (1+ndirY*Gy_flag):end, i); end end return diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m index 360a1c7..18db3ac 100644 --- a/toolbox/internal/_sensNew/testSensNew.m +++ b/toolbox/internal/_sensNew/testSensNew.m @@ -4,9 +4,11 @@ tspan = [0 20]; initialvalues = [1; 0]; parameters = 5.437; +dimy = length(initialvalues); +dimp = length(parameters); integrator = @ode45; -opts = odeset('AbsTol', 1e-8, 'RelTol', 1e-6); +opts = odeset('AbsTol', 1e-12, 'RelTol', 1e-10); %% Preprocess datahandle = prepareDatahandleForIntegration(rhs, 'integrator', integrator, 'options', opts); @@ -34,8 +36,27 @@ %t = linspace(tspan(1), tspan(2), 1000); %t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); t = jumpLinspace(tspan(1), tspan(end), sol.switches, 1e5); -sensObj = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP); -[sensT, sensSol] = sensObj.eval(t); +nt = length(t); +fdStep = generateFDstep(dimy, dimp); + +%sensObj = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP); +%[sensT, sensSol] = sensObj.eval(t); +sensFunOld = generateSensitivityFunction(datahandle, sol, fdStep, 'calcGy', calcGy, 'calcGp', calcGp, ... +'directions_y', dirY, 'directions_p', dirP, 'legacy', true, 'Gmatrices_intermediate', true); +sensFunNew = generateSensitivityFunction(datahandle, sol, fdStep, 'calcGy', calcGy, 'calcGp', calcGp, ... + 'directions_y', dirY, 'directions_p', dirP); +sensOld = sensFunOld(t); +sensNew = sensFunNew(t); + +%% Compare +sdOld = zeros(dimy, nDirY); +sdNew = zeros(dimy, nDirY); + +for i=1:nt + sdOld(:, :, i) = sensOld(i).Gy; + sdNew(:, :, i) = sensNew(i).Gy; +end +plotTiled(t, abs(sdOld - sdNew), nDirY, nDirP); %% Plot directly plotTiled(t, sensT, nDirY, nDirP) diff --git a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_p.m b/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_p.m index ec6bab3..fb81e25 100644 --- a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_p.m +++ b/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_p.m @@ -23,7 +23,7 @@ h_p = FDstep.dir; % If no directions for directional derivatives were given then the usual sensitivities are calculated - if isscalar(directions_p) && directions_p == 0 + if isempty(directions_p) directions_p = eye(dim_p); h_p = fdStep_getH_p(FDstep, parameters); end @@ -60,4 +60,4 @@ data.SWP_detection.parameters = parameters; data.SWP_detection.tspan = tspan; datahandle.setData(data); -end \ No newline at end of file +end diff --git a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_y.m b/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_y.m index 50688b0..92f0c43 100644 --- a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_y.m +++ b/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_y.m @@ -23,7 +23,7 @@ h_y = FDstep.dir; % If no directions for directional derivatives were given then the usual sensitivities are calculated - if isscalar(directions_y) && directions_y == 0 + if isempty(directions_y) directions_y = eye(dim_y); h_y = fdStep_getH_y(FDstep, initialvalues); end @@ -60,4 +60,4 @@ data.SWP_detection.initialvalues = initialvalues; data.SWP_detection.tspan = tspan; datahandle.setData(data); -end \ No newline at end of file +end From 592cd8de030202657b208cdca0772a8013745fa4 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 24 Jun 2026 10:31:17 +0200 Subject: [PATCH 13/24] Fix bug in finite differences when all directions zero --- .../IFDIFFDerivativeFiniteDifferences.m | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m index c9db43d..b056ddf 100644 --- a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m +++ b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m @@ -41,15 +41,13 @@ nd = size(v, 2); df = zeros(dimf, nd); - normv = vecnorm(v, 2, 1); - idxNonzero = find(normv); - v = v(:, idxNonzero) ./ normv(idxNonzero); + h = this.ht(t); + [v, h, normv, idxNonzero] = this.scaleDirections(t, v, h); + if isempty(idxNonzero) + return + end - % Assume that h is a column vector which contains a step size for each component. - % To determine the step size for an arbitrary direction v compute the scalar product of h and v. - h = this.ht(t)' * v; - v = t + v.*h; - for i=1:size(v, 2) + for i=1:length(idxNonzero) fh = this.f(this.datahandle, v(:, i), y, p); df(:, idxNonzero(i)) = (fh - f0) ./ h(i); end @@ -62,15 +60,13 @@ nd = size(v, 2); df = zeros(dimf, nd); - normv = vecnorm(v, 2, 1); - idxNonzero = find(normv); - v = v(:, idxNonzero) ./ normv(idxNonzero); + h = this.hy(y); + [v, h, normv, idxNonzero] = this.scaleDirections(y, v, h); + if isempty(idxNonzero) + return + end - % Assume that h is a column vector which contains a step size for each component. - % To determine the step size for an arbitrary direction v compute the scalar product of h and v. - h = this.hy(y)' * v; - v = y + v.*h; - for i=1:size(v, 2) + for i=1:length(idxNonzero) fh = this.f(this.datahandle, t, v(:, i), p); df(:, idxNonzero(i)) = (fh - f0) ./ h(i); end @@ -83,15 +79,13 @@ nd = size(v, 2); df = zeros(dimf, nd); - normv = vecnorm(v, 2, 1); - idxNonzero = find(normv); - v = v(:, idxNonzero) ./ normv(idxNonzero); + h = this.hp(p); + [v, h, normv, idxNonzero] = this.scaleDirections(p, v, h); + if isempty(idxNonzero) + return + end - % Assume that h is a column vector which contains a step size for each component. - % To determine the step size for an arbitrary direction v compute the scalar product of h and v. - h = this.hp(p)' * v; - v = p + v.*h; - for i=1:size(v, 2) + for i=1:length(idxNonzero) fh = this.f(this.datahandle, t, y, v(:, i)); df(:, idxNonzero(i)) = (fh - f0) ./ h(i); end @@ -99,6 +93,24 @@ end end + %% Helper functions + methods (Static, Access=private) + function [v, h, normv, idxNonzero] = scaleDirections(x, v, h) + % Filter zero directions. + normv = vecnorm(v, 2, 1); + idxNonzero = find(normv); + if isempty(idxNonzero) + return + end + % Scale each non-zero direction to unit length. + v = v(:, idxNonzero) ./ normv(idxNonzero); + % Assume that h is a column vector which contains a step size for each component. + % To determine the step size for an arbitrary direction v compute the scalar product of h and v. + h = h' * v; + v = x + v.*h; + end + end + %% Step size methods (Access=private) function h = ht(this, t) From 6390a533a2f478123423f5461a81efc69eeb77d1 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 24 Jun 2026 10:32:19 +0200 Subject: [PATCH 14/24] Test effect of FD step for directional sensitivities --- toolbox/internal/_sensNew/testSensNew.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m index 18db3ac..b458101 100644 --- a/toolbox/internal/_sensNew/testSensNew.m +++ b/toolbox/internal/_sensNew/testSensNew.m @@ -1,7 +1,7 @@ %% Setup % Canonical Example rhs = @canonicalExampleRHS; -tspan = [0 20]; +tspan = [0, 100]; initialvalues = [1; 0]; parameters = 5.437; dimy = length(initialvalues); @@ -37,7 +37,8 @@ %t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); t = jumpLinspace(tspan(1), tspan(end), sol.switches, 1e5); nt = length(t); -fdStep = generateFDstep(dimy, dimp); +h = sqrt(eps); +fdStep = generateFDstep(dimy, dimp, 'ht', h, 'hy', h, 'hp', h); %sensObj = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP); %[sensT, sensSol] = sensObj.eval(t); From e2deba92ddb21d364ad7fe36a8faff302046e24c Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 24 Jun 2026 10:33:32 +0200 Subject: [PATCH 15/24] Enforce output compatibility with legacy sensitivity format --- tests/TestStateJumps.m | 4 +-- .../analyticalSensitivities_test.m | 7 ++--- .../sensitivities_CanonicalExample.m | 14 +++++----- .../liveExamples/CanonicalSensitivities.mlx | Bin 125751 -> 125753 bytes toolbox/generateSensitivityFunction.m | 25 +++++++++++++----- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/tests/TestStateJumps.m b/tests/TestStateJumps.m index 5c06e22..af166f2 100644 --- a/tests/TestStateJumps.m +++ b/tests/TestStateJumps.m @@ -195,7 +195,7 @@ function testBounceball(testCase) sensTimes = [t0 sensTimes tEnd]; fdStep = generateFDstep(numel(x0), numel(p), 'hy', 1e-6, 'hp', 1e-6); sensFun = generateSensitivityFunction(datahandle, sol, 'method', 'VDE', 'FDstep', fdStep, ... - 'CalcGy', true, 'CalcGp', true, 'Gmatrices_intermediate', true); + 'CalcGy', true, 'CalcGp', true, 'Gmatrices_intermediate', false); sens = sensFun(sensTimes); Gy = {sens.Gy}; Gp = {sens.Gp}; @@ -257,7 +257,7 @@ function testSensitivitiesSimpleVDE(testCase) rtol2 = 1e-5; sensFun = generateSensitivityFunction(datahandle, sol, 'method', 'VDE', ... - 'CalcGy', true, 'CalcGp', true, 'Gmatrices_intermediate', true); + 'CalcGy', true, 'CalcGp', true, 'Gmatrices_intermediate', false); t1 = sol.switches(1); t1Minus = leftLimit(t1); diff --git a/toolbox/examples/canonicalExample/analyticalSensitivities/analyticalSensitivities_test.m b/toolbox/examples/canonicalExample/analyticalSensitivities/analyticalSensitivities_test.m index 3e615ef..c4b4d6b 100644 --- a/toolbox/examples/canonicalExample/analyticalSensitivities/analyticalSensitivities_test.m +++ b/toolbox/examples/canonicalExample/analyticalSensitivities/analyticalSensitivities_test.m @@ -7,7 +7,7 @@ tspan = [0 20]; initialvalues = [1;0]; parameters = 5.437; -sol = solveODE(datahandle, tspan, initialvalues, parameters); +sol = solveODE(datahandle, tspan, initialvalues, parameters); %% Precalculations for sensitivities dim_y = size(sol.y, 1); @@ -16,8 +16,10 @@ %% Sensitivities VDE integrator_options = odeset( 'AbsTol', 1e-14,'RelTol', 1e-12); -sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'integrator_options', integrator_options, 'method', 'VDE', 'Gmatrices_intermediate', true); +sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, ... + 'integrator_options', integrator_options, 'method', 'VDE', 'Gmatrices_intermediate', true, 'legacy', true); sensitivities_VDE = sensitivities_function_VDE(20); + %% Analytical solution yA_1 = @(t) (1/300)*t.^3 + 1; yA_2 = 0; @@ -89,4 +91,3 @@ sensitivities_VDE.Up{1} - U1_p; sensitivities_VDE.Up{2} - U2_p; sensitivities_VDE.Gp - Gp_tf_t0; - diff --git a/toolbox/examples/canonicalExample/sensitivities_CanonicalExample.m b/toolbox/examples/canonicalExample/sensitivities_CanonicalExample.m index 818973a..d815300 100644 --- a/toolbox/examples/canonicalExample/sensitivities_CanonicalExample.m +++ b/toolbox/examples/canonicalExample/sensitivities_CanonicalExample.m @@ -17,9 +17,9 @@ %% Generation of sensitivity functions tic; integrator_options = odeset( 'AbsTol', 1e-14,'RelTol', 1e-12); -sensitivities_function_ENDfull = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_full', 'calcGy', true,'calcGp',true, 'Gmatrices_intermediate', true, 'save_intermediates', true); -sensitivities_function_ENDpiece = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_piecewise', 'calcGy', true,'calcGp',true, 'Gmatrices_intermediate', true, 'save_intermediates', false); -sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'integrator_options', integrator_options, 'method', 'VDE', 'calcGy', true,'calcGp',false, 'Gmatrices_intermediate', true, 'save_intermediates', false); +sensitivities_function_ENDfull = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_full', 'calcGy', true,'calcGp',true, 'Gmatrices_intermediate', false, 'save_intermediates', true); +sensitivities_function_ENDpiece = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_piecewise', 'calcGy', true,'calcGp',true, 'Gmatrices_intermediate', false, 'save_intermediates', false); +sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'integrator_options', integrator_options, 'method', 'VDE', 'calcGy', true,'calcGp',false, 'Gmatrices_intermediate', false, 'save_intermediates', false); toc; %% Sensitivty calculations @@ -35,8 +35,8 @@ toc; %% Plot sensitivities initial values -sensitivities_function_ENDpiecewise = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_piecewise', 'Gy', true,'Gp',false, 'Gmatrices_intermediate', true, 'save_intermediates', true); -sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'VDE', 'calcGy', true,'calcGp',false, 'Gmatrices_intermediate', true, 'save_intermediates', true); +sensitivities_function_ENDpiecewise = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_piecewise', 'Gy', true,'Gp',false, 'Gmatrices_intermediate', false, 'save_intermediates', true); +sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'VDE', 'calcGy', true,'calcGp',false, 'Gmatrices_intermediate', false, 'save_intermediates', true); t_plot = 0:0.01:20; %sensitivities_END_plot = sensitivities_function_ENDpiecewise(t_plot); @@ -97,8 +97,8 @@ %% Plot sensitivities parameters -%sensitivities_function_ENDpiecewise = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_piecewise', 'Gy', false,'Gp',true, 'Gmatrices_intermediate', true, 'save_intermediates', true); -sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'VDE', 'calcGy', false,'calcGp',true, 'Gmatrices_intermediate', true, 'save_intermediates', true); +%sensitivities_function_ENDpiecewise = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'END_piecewise', 'Gy', false,'Gp',true, 'Gmatrices_intermediate', false, 'save_intermediates', true); +sensitivities_function_VDE = generateSensitivityFunction(datahandle, sol, 'FDstep', FDstep, 'method', 'VDE', 'calcGy', false,'calcGp',true, 'Gmatrices_intermediate', false, 'save_intermediates', true); t_plot = 0:0.01:20; %sensitivities_END_plot = sensitivities_function_ENDpiecewise(t_plot); diff --git a/toolbox/examples/liveExamples/CanonicalSensitivities.mlx b/toolbox/examples/liveExamples/CanonicalSensitivities.mlx index 9b8f2ed945568518863c44bc052b511fc1cd41e3..d4486ded3b73a93b7f3e17dec967a54e8a99306a 100644 GIT binary patch delta 101017 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 z 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 V000002mlBGI066w>*xUh004;mRmuPW delta 101010 zcmV(xKb@Q?f(7O%VZ0~@eFldRkw3S3H zNyYIV_P^gVBqdvp-*So5{cuGSTNF8*89p=fjFdM&+@%S-6-vi4J8AUV-3Aj`Aj3Et zpEQ2CzBqi{_~GrF$x$eSA{Cion4jsR$w?zJCO_(QbP$P@>$c2AhI=EaQf_dm#+`{& zVXl8KiGff1W9NqHdq+w!{h(?EQ{2G*l zi5M9g>r{*EFZ1?Prg>qo6FU1$0so2?o50br(uQRMt~1j5h?IY^9+pW#;9;X83+xw<+@H_RH+!zGAkvUns?3|e z+?<}hyMA{=Xm`=wJUHH)!{iD3I~Koub-afU0=3MviuAw$&bWy|EliW`zZ>dnne4Y% zPaO7Mw)Q`YWOm($%#a(72n(Ur3CjUEfa0tgyO8SAZ;Bn7`$3snd}jIh{u6&>?avg$ z6*;DlplZ%W4=~3oi3#^Lh8}xH=R9NOzY})TW&Q3KGTH{bk9Umsj%j!voBxX?jj5x1j*~jW&@k|GN6+JbO|0Y zB}s5&S*lS^;LwTpSLUr=8C8GP=52Nz0Yf%N)Kj%C5nqLZPt9RW6<{tT7IHNe1wfbX z5Xzjd+w8PJ<;V;Y&>9QWh0KhG%L0AUNM$B*gh3fRm0d1WR^(`1Dm)E)~?BtUi@ONH7HQpJ!*?13rZL#%(z6@Z60$s>o1 ztVrEVe7OwEiG6Qtb$1H@0c=8LH~=id@ew1aERUUW%~8U~`thDW|L56YR3yo&diNw7 z*k&JLGs;lt`;aA7OIdkD1t2SQ1J z@P4ayp`B7jy6X{@F;VG8Wc;B-Z>Nx+1>dt|+0xhAmv|4TIv$)4x2iw)z3cKgu%CfW z*lo1%5-mEx(q?~%)s7W;3W8|#zMwh{`lK8lG)obEF&HZo#74@n7|j{rQ3@tFEX)jc zBMulUiXaO><#D-1oAitr_!lum=c1jL^0lW*Y|tMGzE(~rc`PELgwe{=mP_FTLck_O zUY_-}Hm6W`I?E==Nzr0vLVO!XIZ0H3qswFkjiE3T0k?m+HC~{{1K@F)d6Jhs{Kft{~S*$L`87zW7n#`HgQ^IUQ?(Hi5w+c!>+(!Sn(;U0M}(dt#N=X!qSH} z4V$wVJr?U8b=$q8eis>G5h*r|*T;F&+(TFyEgRx#$w~*w)p(^P@T1O~_txD%^E5bm zm)L)*Y{V%F(Cj@%8f^0-BjxIAkslJX12Y=N2|~lZ%xGBIr>^37ZjHkBvES{z=Jq8= zP-qb4f2RpfLL`ESJb(hi?R%H{BzH927=`H>3Id&6X0cYD~aSvB_*tUS%Cc`ujD6Ir;WM9f@}*DIf$)pEi7HLj{$W7EzB zPm&=IzINQ5#SFKL*G}iIIefmPGS{6f1jk>!KA9aPkT-Q1PcuC0Ho+mMk*IIDIlmTA;qF+9DE8wxv7+TD`n zIo9}S#<-sRKMhHK7V7H_S+K_A$#ED>p%YkZ%e4t8GyKO?r`GV-p4FZwk2;qnEzeS$g?UR;)DgUIhGy8MRxBmrDO9KQH00008 z0000X07M(%SqRtx0FuoD01*HH0By5@3>5-@35p^`ilYA-BMkblcuo@k8j}U_uVfY{ zj|?HeX5U&1JUJjWWkT+2bCC< z;IHoi{*gPL{rs+f>g#2J-!3b5q8oZRn_n46oB^5*aDkhy7l_i|Nb6eCWY0*>W+dSW!KmHxv$|J+w#IXO8jZ%z}>=Wccx zr+;sY<~po;YNM8y(D!;Nwdy>%Ypxo zeWbhY0m@ZOH9%h4|0tKowV6MD^-e`i;QDj3^)~p=1@nCUYpeJ58nem_I|xDldjI~g z$68fw%xETEJpQdN2;X*pRWPo_vZT_Nsg5tuQ|`Y%WR=6E%fy-nd98Eh{!fEyen4Bf zz7faB3x4(BY|e6De{SoS1>0zU_(kTsPw5>7ew3V~sGCBl6-jJ}#8oPZqG@NTq$rA} zxo^Qd^FnLC(v0ejwnFgp`DEm8c)`oQ?^|x$mW3Ma>l-byN6@q=(=bd?dLdi9f2JG9 zgS+5VSD#Tki02!F8S8`N_*k<9IGxd)B1-=1{Wp)0D=43ESD11y(GJVS>qf8!pinIdq(b^YlEXLQ(W_9tTc^>Tuo7 zzT;-uG_*ekv2}fB;U1q{e`^i9DHOwG`IlS<5g{W>KF`NP7R&n-8?W{Gw;x?PPOF`u za|Q*|;+7Z1P1-huO)H~x zdzG)Nx}Ae7Xw$MF?!CifNGwpHARmnUPUYe1Y2g^!W?$DuaWquu%Qb6IlF2m}5jbA< zG_y|MSN8bccF4JGwC9C)U&;HbyevP=;Qc->+gm?_Bc@XU0t16=MZw6?c&s@B6=wf2 zVHh49*F#bweqYglhi|@jk!76I-_fpoL_GEIZu;^>wtYR0@K6X8@yRU9qEj#)jfHPQ zJhqNb`Y{rg?&tY3PTcfKlH@h_3(HCxA`<;#NYdh~_9?`%lp3?T?;PE{xL_nPm(fax_~OHpKh+z1x#r!W+BuBFhe1AoU6;*hfDYoCMZ&lA0g7b;1>^Yy-_g)HrgwKlURosisr--a!&3%yrvKc3$RgbWYh9%6IL-Wt=?`-5VtjA! zhP)4m;;N!Qmn&kc54WtfG9}hpF$f}x(GAnhb(oH$@z{rnm)9HU)-x6MoA?RlAc>LaPx@#`IU z#BIBO5^A_!-4ENh*l$QEbK8lw@i-ehYX(Y2LPg=c?hCye414G2c@k7+;EMYN7l=E&-m3>t$z6+F=o=@zPj!nDHZdG{J0J_#eqg&NU}cS!<%gZ zA5NSunyy42(gsDn3v{% z>0^>56fUf{jC}H8!0@afjLnx-*t?p|LN zzy=H_Npje*(}F~&Xi6zF?y>4*2GKUWl;(lTP+CgStS$ud{hnvFDEMwDj-DkAhckBB z+#?VqXO!#@h#oo0EgW_cp_-4uVWF;nr5XDru%*Dy*tW{@;~@$aLUPWKDg{iU6wMce z2!{$P@@7*uL8bWWsk7_JsM>|COWXH2zq9=M)Ek(H$6L1u%plhA9ld%23a|5120+_* zVH8;C7C?IphaI3+5kh*-zO(E!?Dh2*LVFQP(E<)}Vb@C(W zRux9CpT3zxrMUqv%B{=_)N|iq8q!teX_}gcTx{LqbWP-9-M}mWvwR1NQ)eH4mOi2? zmd%@&cq9;ESHWHwlSN6052}TKM}$Y$3(_u&%5Xamp~ld3+2J(%WP*2+ z!gWM5Ue?+EE8*3O#ob;^Q0bGxB>-v?sL{QCqjj~3u;3g``sJa0sb`G+csO?lsU>o6 z%2s$<;g7wV8y!~Nq0qD_7yV~Xq}?dKul?$0f~6*b%|vqbwKVUZjSl30N;okth%_@* zJHS$!F)$9?C@{?y7q3t;43QH}efx_bqNqw+a?A35F;$c-2klyc_=ei7xO@51hk@ka zhj}4Zs5g557h`*kPleIIQtbBHf&n$9U*5Lor+qvO-L49oL6J9tu|-!P48xqy_z)3! zva#E3Z>^<4lCt&u6;PXh*)dCbnC6WW&jJ7ODJ?P;m{W)gkIkSyTQDcj19goz`3;`~ ziRODUk(ufUYu+wWTQwHi7peOd<~Yym4)mr-TOWt0HxlHv>Px$xpu11FIllY`c)nmg zzyO})=ZmPNDjcPHu!aoqs+Oi5;fKLvhA=9lLHlqR-r*~iyxk~&pKXaNXt4DI;F)G$ zkGI(&@$^uRO(Od=mc%75_@)BwYbv#zokC%Uq076b!FL zOY(;QKn!7)63xh}@Y?DDlT03Rc%8AvTQUe55`%Nh-cD10fx+o|R7-3$-7BVV)6NCS zhQ0Ua<@z6vl;gy^`!cy{xAM-f1YK?XCSMDgbY;=)0}O+y&mIu;QCeheV1}_QHtZ?> z-Zf&%FEavhJHoqD!1z-(6C^!+-K$|H{n?Ih+q7cYx(*7Gm8fv)+dnvj%IXtOtJayb z4loSneZvKR697g!_Pdnr`4*l!IVy_)B2H%+wMc%&$uWw5&uRp1Q_4joz}En}SS2!&3fU?B`7w%*XpSZG|e0!5Vjvm&IZfz6 zfS(Y0tbXt`w@i4-3`0=VC8*W;u#$?fk1$W%mn%3;O@3YpH$1&Ihm!?J1_Ii;d3gDF zyxeDh#c$vI_4?4cw29x#6OJ*yoagNwZXr5P&yZrXOFwB8FMD{`n z*>33)-0)Uf+};yIRp${7GE~2TH}+#wb!^~!0BgA#3peR(g0)8QToIvF}%G$(4`cE_=Q zaj~?JyNTU2GzzEz{x3~ac9I`#VuvxAS6DaUimh`FirP0pcCKIK5@12>8sq;i(6nNR{sU zM&563W$Rb(rn?`G#6Tk{g1@V-cPul1>Y(F7!a;*xU64*+*1)Kfhgp}`BTvHK6EcQ5 zZKmghB4X*$@GLUGtOqaJMqlbAvW&-}f%0O!0hNnSYQlrWezwLP-FgTK(MTXmHAon> z3v!$uCInYynZn=BQ&}-`c)#qg%lRdDT6P4b9xt%FHlKyUG*lQgtZ*#y6&V+fxE9xsKj|FMwp&+h*LoH_=q?(?J8gva@{+UzR`;Mx;m#=ht&ki)^a#A>u z=bgBAEzZO@m#Q|sRjl|OXL^f^?oH0hFbvxkkE6()B5n}FQ_`DvZ_v<59SGBOtoSyn z2ItJoH&9)n)rGtDp{-k|+UFUCC))p%<(*Fj^sRZz@{x zP2=Zh2JqD9&UbjA)AP4~nqUrJ+=Uhsx%LDD+{kS5FE}#ER*|K)c!k%GPE{?;aGy+b z(%iGdO8w65w z`ozxXc{M^KUt=#(v9wJJsi9~zNYVM|`=N9OuF~{VZKsQkG1N8U z6FWBM-_|K>AySHF;GaPX<3uCFns1r)$LHUCJIKA+oi^91fP*Jq{C>sy&|70LRo5CP z=xh`-a37nZCwz2&S8rpIRNTJq`yg`iEsG2cJS7c{F;C&Rs2WMNJpqPOR~qZa=x zD?-&bm+hKPykS{>rH8%NQ5i0t`4)KI&)KT^{*}j9u{-S6fQ7BEjN^I=kmW!`cK4k& za9?h7#+1fGsu^rjLb7xA_i^4L}RydL!ijVKRu|>UD zm1$GNCAulN5sjvaslS5OH4_Nr>-WTepR-VLJ&d-M`zk-BH>x1a4@crhl!bO@+5`jd z!YpU=+)uOc(uNSF7(5%))tDkegZJ;1iumzH=$@eV-!jWA&9=*Xj6Cp;lBd4r*=Fu7 z1A6f^uTFq}U%S)vO52$-2aoX!;w_k5^cy(-LP!TOX3|&bew_I_$u@oXA0GBb+A$#2 zP(9^5nW+W-$y;772492h=w8(qg`;V)A;rEpyrbW`v}R2g#~AGT8cdYag07cS3i4$d zk;KlA-}Wn2L>lgV{QYS_8mQmRxQ(L%0oF||uX_f6b~=T+4404cxrnJ8Fdl5<*FV=V zCngM%!*sOo0Fw94u9st8*Df?Vl!uVQi*23X3yX!!&9^T|Io5(2pFT?Z_q?Lux;&cLJbP)RG}=EN zT2TmpE;jDR)&h6LgX9jOFlW??R}(F`a^6WSPhUp&iGOU4wrWZR zd3+PHyIq=E_lY#sC|W(WmR*T=?d?=Le@sJv@7ppB@qVJd>2Ey|SMlsEvw^wsdLa^& z{5)~fsj+l9&J$;i{%+u*P*VL)%=xiHe8f@`2A|x0Q;lUNM>kD`qI11Mu@&MW(nmpl z9&g(6`oXFF0dU~WVDlPgqK!(m6dkN^VCDRt(_`TXVrh9r5m@#mq%jG+#YEy~{>V0e zEhtvPsK2!h;x|YEgVthn03~anUiKkEG1?nwC%o0AGuzKkw7_>g5?JZAv>8(c6Oez_ z|6Sf`Cj60v8srUmzHMvyXuVs@Q|(KuwJ1C|#Zz#%QE?tg zVk8g@8R*R8|;H1t++Sg7b7K)S2_8+Ao;X_grke?6m=iM*CW(KVf7 zyd{8SFB{+CJ)>@J!-P7`ZT+u*_4mhY5>4DY+YDR<1j*LzH_E)4ulMw>e#@MS%6;U^ ze3yj3fb{qwW7N(+4cy)Avw50(%_6E<1?Y?toy~)~8Hey-MsLq!HvUwx!oTD0eh)B{ zMJL0ot!gpPL3LUB6HhPZL)2hM z<~1*`#O$Yll;r>>dYHSCE}*@EdonE!Kc$}SW2%uSo&Ylt8??O+PU z?4J%NMjp}(OKc9zxwSr8kHFKY3p-uwLAILY6=Qs>96>YsAo<(tfeIdJ2bHKI8JWLF z;7MjOvj-ek4Pz0)5Tz}DrL+^wNZj5I`E?GB?)nVnOOX+#>h|d=TB^9clTmyTWao!k zfR+8of_^SvE+4&|qZ+ZkW;+L~MkJQ_gLt@~FS&sE!qI$EHocxDK_o-XD-Nq3KbsJP zED zd?(tYiqVJ`R}VOEVu1lia0qQawO9qdeqaVYu$mSUVH$Yti^Wr0!D-V0zGXls;8nlf zC!sJDS*duHyC-9Re?y)*$;1YF9=@M)Q)hUgD9QoX5d552C^B9+TmQ8u$@84~^>Gy~ z9i(i3o0JL|Zx3msZRxCu0fKgD#HZ&j$9bgQ!WJac*&Ft4nrCq!?Xs7}J{G^egm`{U zmwi8Pjrvj)Roa;RFd2ZV1Vh9ZEhC@ia(d>s&v_)xhP}UkXMdh)KN~;bz1cwp^&mKM zCH}1MS@+i(p4u^=KxuMwEVLt`V8+@h3WI4mxWaJas)AD$%xHT+Ouj zjTLgkwI4?*kDLQ;h%Y}k_Uzl!H0%7PQVUm6edc zvlQtU`PaTU_t)8i8C6gZ_i91ro^~-}?|d$h-23|B;9XB>Av#8e|TdU~Hv zo*}cn)lTyCKZP4rWAT=h-3Wr#eE=)yFX4mqq6|ER&F7p5x_kl`Z1^P2KoXiD!alP8a z`hH*2PiNbbb7bs0O;LKJw!p6H{*p}wA$kW&ta}(R$o|bwsrj>qdu;(qcrkl&vUVCs zTFx5#)mIfeuLI&4!(TBjGnC-3_$Weulx2^5*amZj@C^$7KvLNS{Pmn4Bdb?KfZ4&D ztU-Sh4+F`(slB3hNIZG7Bhc1p+lQNYI9A`hxm8Vm`;7T-jFoqira}Jad_Zre&G1#% z!09B_{)n^6Po24TZaDW?(1Q5EMDO(tmE4YozKgCp<%z&z4HwY@oq2_-TfG5)KQB)U zu)%%#7>`vd4M8e$b|IXcFQkxZg%U<_tRkwU?=ctyfeW29t!+T5k-IW z{s#J&(r3PVW8pZKg$?WecpKe+C>!WHKN5F|cPYyt=`VR& z@=sJpFt=@6-^)UGMFLMkKV)GGp*mpYcTPoq93itChVke80j1^vjU^0!o)&N;D7fKa z0`Sp--4!+&<#}CI55pdWfwR;(I0c^raZGS;jAGiybF52Gmk_|}uQAC-{`Cl7bM&-i zb;fi&w(BPI))?miHyaJx1XBlF`X0`W_Kjyf5$}!5ez|k8vOGUPuKYINV=B)NCLE6* z7AUK~k%WQa2kX2moDbrEauN^#1tr$gH4!bPM|WXYB)@gOGRSN!UJPRQLEN{zjI-(OM(o>w(gLxgMNemA*6S(sBLpITp+~f**+yD9Q&rXRmJO(gvJH!+ z?4UYuUuIo*hd5ER8_HRRFDDvEJA8079uQ@BXQch6-!(DD30pMtxvjYtyeA^lGX*b7eCFaJB|(+FUyaL#jTQDckXyV_xhq2T6V zO-HaN!w-Sp$eLKPGrm?*X07%TRDELl{`<)bgQQe5rkBr(rA zbImhLO2YGnh_~N7t;o#@h@3}onm%qi9lzh>DeKSd0&KSzI1RM&@V{X2_%>#@c;%m= zkDj-;W7Q>aCCXpKXHC<#>mWXkNu0~@Z&?Q|G7J56VIw|J#Uq&9nw>*UU}$#_e}-%-arA<5z7<=h5UfMh4=(#QE*&-!F??d2>|>9Z&ZSUTh~Fxxm!Vnbc~*@1t8 z_h9JgYk8@%I&@|tP9g}$w2iK8>Pa&V% z66hYg13p=-lKB4S1O=RqQiI$kYvpQ_H?aDg+XUOo*qf%=-RNHTJ@?z<;#FPc#`q!&27PB67EbrG*9C>VZ~(Ns*enPHd>aXz(cSn zue#)aN~-nxj_<3LrQdQvTwAW7+L+aKm-vM_u3F3AnWo%+peQWhI8G~EeY{J?d)q3S zQJZmW49oz7`d%rD_N$yrYtz-cheZnUMv$*YUNR@cSJw6vFsE>Gh)syC4wmIu)(<=` zl$ZW<7YT(ZAP3^{cT9nRSMmBFGs6YJd5GSBtcGk7jMyy`ulapjM^$Cg(PZ)zhTPZ@is;1^76vZC9x07b<&jL*D-K`f{&fg8b_B zhfTSOSGC6(pV3`piyKHos^TWbqm8bYMh7AjjIqu5wJ9vvOGokJO#kg@!;o$}0Tm#>iH!0fHGLif|hWU8)j&8W-p;o$0O5S^t z9}(y;7Jc3+qtGw?&-qQ+)Gn)94O1b1DI5xqbP+T#Sqp!<6^7Kr3-lxh1df;S$9rdN z%@a6V6Gnr4Rcf>)F-Ty4V%s78&LXwaZ^v7&CgG?90TwmaU(4|iGzdF+Tl(nTA2rCQRLEAWx#a@-c{KFIBz7JOUBBUz)&NjSuAuR&w)$^k7mB5?e zyQ?#w^LG^MGov4`=EvU}5)jXS!SBN$-ukr&^|aSD_sQ0vE(&$uK;MZde5a-;Nsv&k z8C3qxsu%}<Pmi#&ZKnk6&&_BFunR`CMx*9_EZEL6F%l=^IB``6`<>VQw)4|Fp0!uADH=aU-=ePt8N2zE zB}Ta~*07(hRZ*@}1AQ73KydHF#f7d~v7fdQYQaRxrXFrh#fNs<(&SlE3x+a7mPOweQo=o-Ty z9e6jK3z2kKAYr^};O$i{S{@$>IY}RZ{Jp^ie?%r0#3Pc|vDd19r2d{6RjtI)V8v*| z-`x5g_8EU{NCZCJ4Ym`9*R(HGDT5DliA$J8u0Hd zA4l?_AlLVxis!^SDBZh=6+g|S9E0M>L$`HeJiXzJ?s2gp6A&MDfmR!2oT2&l;gMLMdn7u)sq>Bz^Ap3(;R8yIK<7zoX5*h>I zBXyP(`17{>olg)Flnox2e)>x^o|=>{?5cTxY1pf@S#L&YwC|oXVM}_LkdM=RS6`A= z*L5xV4;`Cs4(EF!&8R=quwxjqus#fnU>F8tMT2VFc6V2Qd3Zj0%JGt02bxKXdbJWf zzue%y^K0T>V6OCCG0k%Gs7co^(~mnE62KVw=8PW_AGh~Z2(99%l1SMH6|M4h&N&Rc z#NjmEv8V8^zxTtV=t8TG`@B?OS2*k7^wo*I;ce+vFbm=14*D+4(=`$}OmfnV%Iww` zSiK!jI`0;L85ON{Sq>B@ToG z523w(H1T8ht}2_*Q-5sC%WdmG2i{gszj~)8$(3Y-IJdbj`xaIc>fsD{s1ZB-ooA{! z&uaJL80~0_6F^#`EJgU5KGEZcj(#Z^+J?Ff6H~QRp0#n!!#=al2ze6v)3foemN;$c zAtvLjUHZ+SW2{%#;S)}=u7C?MzXQUMcLa`qyWz5~U4LZT;qj_Rh)XNB@`v^S%CpsD zV_W~v-Zu!>C$WZPUsSalb3a{ZZ|PF1(+S=?j(>8&d$no(YzRVg&MyWt`q?lYj|8v(KnvSW~HlT5VKg47oge`;Gym!nTgI*z4U$Q>vL@4MK1pi)(d0%GEy6V zcnQc*Rh%(-d`K+VSRY!HBwg2V=f1^;1ANaWkm>baOHQg=J`&^V8ySTe*#5bFklpS+ za&oJ7()Iud395YW_f+i+mA$?amL$nDOMm%IFZNrT(rQ1-pdVQ(vdfnYl08{(NYjq3 zxHUja^8+2l;pu<;&bKi%+Th6Seca@K^WVAGk8WF5J899kVjwu?km3$Q6zV3vE!i!U z5AMP3U|#w1gLvgHVBP1%U4mYeHetQLpGO$az0Wrx6@Mf9wiJOXj$E;lEmRQasc%?9KN1o)!-4f(o< z5j+6YS>C#ZbN`LWPvD53aH>Vu2jEoS_81%8K-m2-oYeAIxb?D2ydtu*x$leTKHFO> z6&MXYQNOFv~Mr z%bfTHS~<)KhU4ST?cY1K36-)20ix!-D5`0B(h&kx9roiHZeI;$*q0?2^eB#`MWKPU zYJF4M2FJuMP81|*3|J<(gDm{nLyR5#@byJ;OWqP~HN0!5~*K zJ%KbeEtj1jw_nfKK(W5vq>AzOavV!ZmUW$y+E`9x4rIvo9ku}@9MvPS=U(z2HL*qrFf5G?)a5rMt1dT$7ayr!1$}a-gqn2pLvqS|L=uyPI!@bvLBH^R6Qe|!RNVs( z0HWQl|2#J~v1gCd`8R2Wkj&-96SP;2Jf{N}KWUa#HIDPnliI|Q3$jdWpI3nu?RO<=Y}Oy7mW7>K!@#3ORtNodOFc*2Wl$`jphqyn^chssi zA8Ilf?^I{BdoQ|}{v1R9I&Xnr=A&s_oQ)9OQX&`aOR4YP1bnIi$GBh2Z@EwCBboQE zsf9>I`fa&X?g-^aQFcU^gyUWJ7U?oun~MG@vK|&tnXArvr*~FlpFJ|StN178UMGx6 z5(<~2YT5^Xz*LtU2h^Bc`r66!(xEN%2g0xWnKlm zT$`4Hpe~=joUDEK`E1hpdI#Oo#t6b|FZiIR#`y6nhd!vR#L_lMb3P~03km8^2zdXJ z6-71P?_sfQ=z)k-BRyLLsVkX-IrCt#FEZ;l05bl|*vswwye(uryT_yzK+L23iqE9T zh|Ir#e)$^&tavxWpr}vEc_%+FnVMALdDX^2H~b>LRR&!7Fnprwz@rK--fsh)i}|5? zJllV&Cz0WZTecBz*PR8=HFl~f|6aTeMyF`6k#CO6?>CZGAkr1ZRNiwaULTVcO&I=h z>&-XfKIFUrWIanuz_$-dRc%ik`BK70U9XpaZPxjPXOJ0oa!xLvlWx!7%;^GAbfrjRwsk1V+AHoxnY8lK0edGyG<{VB{f$NHhR978; zDelH`6-#Fp^ZK>C8-QNA{N*`cDTNI=AH<1pIf_m|3yi*d@StB=W0R=vz*AK|AfJ&? zhBm|hpa+85{-p}48S^)J zBLYRGiJ3+&rzE_4z6Nge>@j<0X(TtOo&4sKnHPYkuTk8#YzhB1bt8*XO zxHn}2h7ov0_@NCI3Rv3mbbw0{0B{P#d8!~MhTDyV{P~V7!9Nc7lW^ka$}k!Kc|9cK zh@Cu(XX#&B&e~vn0;~%?HmTl!(Ef_JL-lkC80u2bR8G;`e=@+!SEma}lyhUPoMcdv ziE+l#j3aLK_R5@dK`;zI|KxZLh|^~i{+zv!7Ba0rqQKz>RyoBNlq;z{E63s_jITBiLgi= z$ShB_9FV_P_m>8~U`T`fe||Ar?{VJ5GGp6;Oc=O{DX14tW!1VW-vBz$LEw^%+9UhR(Es*5{2mDX60TkweT%2H*^{SE z6#CnzK8wN;C87C_s(gWolA!h$HSlgg@!X)0pOnJ4-e)>wh7f{(=-L9R>tyPQf@FXc z!})nnSBU=f|BNJU4PwW&+RrZBYi!Peo`C$?ZomUaN!e}w9U+tiwJCi|Fk?)HxV*HI z>&kT|q-fh|dI}0QA5*fTrr9yRIrRd5?m3&oCwb4`t>JBMX(arh@x+u_)*gzj5oLkv z6|JqqYSnQ`ow*r*t)zov&gTKGJSg+a=KYv%D6u}*&~7WjCk;|o*hktVw4E#8~Jkn^^Gr>5(94F^af7f@zpv76RQ7Wt;In4>iDx+QPM0R<^R%(m9=eX;GDJTQv zjBi6x-|b9og}0r&d2~_DSr=E26Y5S22l}0-m)F|`0jXp!7h411aUUQL5kLhH8E{|H zFrgWI4q%yob#+J;Fxn`fF2JKcMANKh+gsZf4$LqRM{lg@IGms;!?I}YBc9A~o->-O ze2v9*25vsAE6!s1>sx-*qAmrXE=&zd-aeusn1Ot(Fmx`z=45W8$>#{#wXXYqKmOWB zlD-1uC=C*4j)L7Zou(gKVM}I3u{VMeFEulq-?=S+SAF_C;Duv0-_|SCRhj(hr`SJ& zlgITk1oPZ%TNGV)C%;e>CGlUJ(srCAxFH*4N~Q*5yqlr>6wjYs==%ql5rkFz*_&V| zUgc?Wu6chxRqx^4>aJ2(`?^1)>^o26`#vhRZZ|MS=O^P3r2^x@06 z`OcD7>fF${fgmT%O`7h!^72dFQgIo{!7CSLfW4JhS*8$}^@UVipO5|r{VHk_-ozDcQkUqmR$ zEkDJ2qn4<5EHC}16aP1RZ_?x-lWYtAAQpg_m(24#2(%Nk05M3+zrF+ISGTIJz1}~w z?lj9qrZOc6JlxOma6f)mqW-~s0!`3;LSkL&YZ)s11bBfQ&0c+AZ$AiP0fLH5;THUV z^PvttL~w$8qUlU0*I6bvkq{(*)^%;ZIC=-1wGD|*PoZJH_V0(Jk4|v_Ze{Q3o=WpL z>z^$gpU>ts&}tqf4Tvv8fZh&DX?P}h-$1bF4a1$#Y|TUuqZhD?y+_yUtI>Na#C!@E zf9i%&4JKxfw4FdpQ95t*X&Pda2*v7u4!(4sG+7l-evIWdHx2b2c$?l$x^uilOL`$3 zTj@4g8rCE9L~%MPbL8z$!UentnPl=Vw|X|cU(8Xrhj~1b$xNi@3GfkT4X6cTJabSC zQ^0T&gFVkcsgXV&pQt;~m2QI4-nB=neCivcwA^Cebj6%xmm#5uA8>%%^eD`KC2@L+ zuPXe91Krc4O9@4PJ%+mS4vkiankJ8geS&p=vhtmk->me$;utqp++$$>KmQt0Zl6f4_$bU8{^1|Z zdu$QxPVpAtRwk8PE;1MTErd*e*-L7c-TEsYb~;Ze&wW(^%l_dVSHd-4EIa8*>&7Ae zY6~7y?22ZW_<-Vq71ip)3;eMM{O+R_1EaXZ;$)p&BAlq|9VkA;$A4-fn4>h z_{mjU(L89VupNPA$#2FmS?~6Uf0gT7uWxIDDVIa|`snrw)rS z_hqqF9k$)xK@_kLu>H-zG}i@5y%VHvO<0OUzno0Hqc{0Fmu2N*`8+1{Ic3=r3#s+m zlC&X+@hiC4D!w>nKqn-vE4mcE$>}_^XlmH&+}&3_R#G0JW!S)>y|D3ne>(>K&Y-_q zwA9jFtehdqK`C}JE_>*VlUr_v#LqiH5Ez$b;<}cepUA?EWU^JZeB@}-p5M`gj^TNyNw@jsB*t_WGGBM&?U(zx3MH|(fKpbA zlcet>sr5cyU3!A&x=frrdxwUdaj`(Al*q0#6qarNXwN+>D(^Z_S;v*lgT8o7Y)~cqMTNmvzVrzx;Bl0y7ZuEA<-Z2q zKB{nIwD@)x0;LQ5f22yz;!&@=r*;Aec#M*UG)1Le6)&U&?obU*iqLF61vqcJG^i@f z>9MON%4ZkoX$2#K5l=OZyg~efnx-~Do7>C@H+l@gP2kzIjybcbd3k- zL{)`}bsxe)MZGUQO?q)qrQ_9-;)Payd+6Bhmc1k8>SL*de-&^fu$lwlYb=Sg5XssQ zYyW@dwRykYu-fb?yrPZo|MBl!F_OqnX?+yKPT$kl9m1;Rp**U9yF(@A@D{o@Rq4s( zdA{G?!DEqi5~9uS_1)L{>P=CuIySa0P9r+-Ruac_FfFSRniYm2hzRhMHIaOMyH87R z{X9bI4{u(*e?)t4>U(Jb?4XnmMsS3ei1phZGxueUksjP(eSs))7oe4rZ>U;)Bs9`L zW}f87kkQLRo}b%SR;HpUR^PcdFHFrtO*8B27-jfgJ{p?3f1bIiJPBAQ*8?8kU;R9^ z-1Z@=4_6V>y@(?T^=!je6%aJ^7DiN`NQUXg4SrE)e};d!iWP-wY7GV4hIJz{wDjdn z7zFRe19ySxlo+8(FyA~4c-UAt4nI?tb8A!b`-XAZd(aw$?}Zw{QOr2sPwYWE1y|T% zFcR|)m)O@ls2Qekr+&|4{JbNB#>H|S11E!h@-gyz5d|X=znJqmZ_#pzFPNWb!S?Qv zreU;pf5BSUoV9Ik7<0n+h!x;NbMSnao8ZJc5qob7d)p46HS%gL(|cP7JalfCZqfDx zzkdxqw+^;sx7239TEqSL@=(EV_?8~iU#_McR{cV zGTY+_36bJ6-zaw=%$&mpp()uCx1#l%p7FAY!Z5v&hZ~?$8QvMMJmT^=h31_R^l|Ss z_ya?8Y!up>KRbUerCDqCTxyQ|Fb44G^H2_9L&OTUrP{ErJ`{G_)=L_XzUq3ax2oz(0(?&)2zB2+am480OMB_2jK~y@UZ9wTfM-`PRrrsN;a&VzZT4E5ZcM!_g{Non z3!IYyxarOR^*gVNkB~inZtS+PG+;9{YnrTMvVy}30xO&>`~Sc8AFoY4ok}XMRJpcz zQJbtzzo<2_eRK47yD1Rt^dOEbYe$$5iG^!-t=UUyYq?LGzu;tre_s!l z&byo*IDFfsd3FygZHP?w(zOO{Liqhb42naTA%T#-#vYFKm9; zxNkdGLAvtshu13C%z3wk@ZKs5ZqFG21f|b`{;&6QB$LCuO0xfzUC!umfZWdKj z6-SePVM6N%?zM(r-t1qeHznzRe`;!GZ3hTN$F9{?Pl;g3BV7Mm(^PY#pAP7vD{wQA z5mq?czx4tJoY^k_P|YiiSc@E> z8(}kx9VOYbUqjiujy^P#Y2 z?&`CTU5fG_aP&G_0R6R+r>GgZ4`eM(EDnEBZM=o{y?U&~v>)%@(c0IYbF;v@?F>P1 za+YPuqw>C3T5pMk8Lcl@t^O?43{?{d_hivo#<|kUa=i*+XxN!we`Ce0p%Oc$dFNoE zZVydudaAym*mK2Uj!V9GO)|L;eAOsQ7)&Arv!PKG4{^C-UpdlF{)k~1D`7gm>L~@* zbCoSg%$0PV?>C7G_n<%DwfCMxI(4yXzmcL=qT}lI-Jbr|dNgFq%3Fv&Qia2?!nQpY zSq|hBrDIu|O5+dze;s|70-$Z!>ihFJ;s(UYV!!NZBySuyn}$Ih>=~q~A@GAZbRxh& zp3i#q-a?6~EBcomeC8ox?95zcx1099$8nr!V?}on{leq8%q4G|@vwW5U#qppo)|Ow zz;_>wEo}^o#XIf07krm2dei~;X4K)!#cM_N6I+$@eE(oQf8ZLxZi(q#j6JvW1`B^a z6#4ufg%d1E(HjN$>ZHWepC*~vd3_uQ=8f$w?S##|`dH96OVVW60&f(vZ!Dd^aS)u4 z2vG-r(j|8 z8vsOs#!>>ee=z_PZHr!O=`nv41!FQ5LA>2}*f8S&|7_*I^Rof*OQ_%QQU%Kf@o@U_ z>Ur*X^}9jf+UVltB`dIpyd0nI7z!I78=TByg<+&ATi5d4|_1J#O*oM{YT3Sz_={au=6m(!3wj`{iDJ_A-bY0lB~} z1r`nZ&S6t+YQ|IjyNNzu<%5#-MEuU&rnfh#wJP44XzK2p&VRn!&8u(E!X(I9{MEQn z%*Gj&CGO=1u~`OJS;3S)p>BBJTdL`-1MCK`f0;cXKYrJIl1H-#askbeLas!@=25IZ z-pED-3~^~Yg|!;$Y|FzMbpphDODMyor1IC(+0IUD>>Ed>fq6IA>P+_F>>Y;DGg$Ca zg;xBO9Ky3%E%yD)$@karw3?mDFEPf(h&+>NyYQm0rEeeU!hvT+n+L9b_^$hfbCYM& zf1LO;XMi1EQcol5Tks-Z{xTWqPCE_r>iLW@?P-_GIFYY&GL|X3v0$-YeKCG`V7x4K zzF`VJ3mRTZLr{c9&d3X79ub|evo^kC`@TKC#6+BLOi`}Hgy-56b5GG~2mId@VboIZ zO_1cpA_9uY@=Kj#T$3N>w2!MGYe-JC+X$h}S5GW~vz!cy2%lg7L0w56+Q=02r zEWb}UdC>j%hn0`Gmr`)~!|(Dx%aF-t_K*J%5WeK7bD^mfE@}9c103-`82KOwhTRqK z3D;|OaAQjgiJyqpihS z7L?NloupR|UmGR6PMTqXQNBj;Mkr^NxHo(|746`Vj5a=fEB1U)oFu#B+k>UX-#IpB zJf>ex20#~)(Io>4Tz6xnt43~feF3ef=Llxd<9L zFqcmD=8F=FqL@kWsZ`{kP+GX3iuGMQF@cd3&)>U_omy}BJfXkJ`Mjy13KT_mgJZT@`6u2f1 z3|%ZE5=kRoepv27q=9|D=IRNNMXm;l2aAk{E-i@Ek@OOHMG&iP>^GI=o(0^Km~N9F z3IevseY5zpfFLxX3N;(Sf1&I>2p7xOYVr;|VC2aZi(fZr;@$N|!2HMlZeHCf(=sF4 zFZ75X)_pK|_&HmBbMbH_yxP>G8oA^eL|$yo|Ilsc;tNv~!_*$N_;1PftYX+lIIvAy zsj7)_I~UdeTTowdwZrDEbY|4=chht|`!8*LR2;8f{rRc6|Ngfrf0A8Czj}XK_230- zN22{-{Y3xzHUTOEJolz}9Z{iPQ2(bMyf|o=M!gAe5)GU~E`53&WT8S~?X za8GuDVECkLXPv(wf7)%Td?VF1tb{5E>lHYD4ZS-(nj5cMv;j2aJkcBQr0k{H`&EqY z_?-74yYyPYO-QUb0xauAA5>CDwyChf9o}=%djGAP4=%~P?pJV{QQBT1zi?`3%eeh& z8ajRL$#+jORZI;4#NJ%?39?}bHg(cMaKnI`8BmKL6G9)}f9>M}o?<<9uWDZ{_vX$K zp>RqNgw{SEU$lBO&AxLEx0vS=z5eDPytsrTUoeQj4eCETL)>EGQF8L&Wvz>}0cjNg zTmwvq?cc8{%D1a`G*$#5DA>%8a}b->i>J($KdfXB9G{d*n0b@aW2d441&gk~60ZH9 zIR%%7>qFq)eO*|IJUZHp73$oiO355nSgcxXew|h>LUm{nD5_f3`>(Xf&jFd7g7(QI?+fk=~~^ zl2-Jbe|0roD9Bm6^p9lM`N9=R{NK$f2n=9s;I)9rF;BeK1gj?yHX|k+gFCi z4UupD_sbodUDx!Yt$a=sZd~0aaVGr3e7gcLG7)9ZGL< zh;=LWg4>^WmUSuz z@3LL}5g&6P>2KBi>XFV9_#_Lb(m4Kp#`t~Zlnk)7FJF5){Pujvt1UX~Op>yJ*P3~+yQebvkhcfUO!8QeMx*mNH7IahAuotnV6A2{h{f^P!* z%4{#v3i;rv$fLR$Tx|-D3&|0E^{Sco##N=A zARcj&Bw1edf&IQ=S3Q03f($%V*4yn~2x4T}4~SKb?OvN1F>)|QF}G~Xf4Hj$sd=BL zUXXEs)R)!>0FH#um8l1V!0}y}xo!lC&rB9Jh)e6SpI2Fm*Sv%oW`o}Ghl7qUenXWd zFo)N*?<7|M;R$*5kMbUcMe-Lvj$+e4kD3!+rKKI~jkFX24kpxHG>_Nj zZ;c3(J~U*L?2n^E@P<#{?&Y^z)n8hl-L6_1y?K*41la)mKBMH`P`31X(brMu=C-~) zUz%50A@p0r+4Ej8Men*qTYxQb<0tQJKF&|`?PZEelN9UwUP<|ke-_C5iAOZMB_^*s z(|RWnBus~^KEE~LoPIJe?5`V%m={dKIC0d*ZQGdW zlXsU6!3TDN4UN}h!sur=i4>{x!s|0iw-DH4JYKFMQ=)wn(P(ZEN14-OgUp^-=PXUmz^|ypSJ=2xm}OIY#6S zfIyozLJkj7=3t3r9%+gqoiycL#Kx@%FoQ0CdEm!7ti0{1v6)y0=r+{eUeyA*OABA~ z1rTl}o+Ncc2b6Y?dv*CiEfGxz7@=ADUCQh3BrqfH(goVq7f zsV_e9ysHXc^d2LsICU`bS*OEZ8UcO`4LhO{65x?0!e(~-?YiycWaL^vqt67Zx*ozP5uUG$Q^qL0P;tbqz$Q zkZVDfN{eLjD2^aR3xpoWac*bKMXT5qGQRb@#*u4J{a>v2 zQ}bRMJC5hSUdhd!@s!*w21P`S!WIVN77%kf!H}~je-4mzTp87!xXX{ z*|8rsqz|w=RHGP7DN9j`LGWE2Y*9G@mASz%U|wo|TZY#QptTM9b|^ve-pP!UWOygs zytU*TtXkOU6@zO=*BNlgKl~Mzl<@hx5hzR7>x>?5dKjiPYP?b2hkolB^pF{CBxF9m z$OXWVf8h<52mYsNO?$S?vKy}6TT{rPGx-*R_P7#7*U@kMNOOC=3)z)mhD?MPg4+O< zZ~;ggfWbm23(W+-+m6AqyMIrzU}H-&~ZTUM^PqugDszTez3Ls_os=_iD5`&sE5CmsxAyrLbAtt$I4*Z`N0eMosk~o|53(cJv88>3Y=^PTwi` zB!yfans;0Zpb*7hS~~(lq`2AHhB~8ke+zC2M1uW==1c9DC0LjBDST7WbP@H^Ea7ZE z^enJ{<1l1A1{D>0$c_@OgJ7iC!+Zn^%C3kB(a5`P)u_~ev*3DT-J|A)PH2j63=E0Z z*3P4*5lE*DAfM`SmTABcAi?CMYBe|dAv zIXyN{sa^+3>Oy@m_;#LEeIP~CA?cTAG&Y zx~M7cRVrERi^85g`+#}#KAxrq%iTZGB$dqvfK!#R_}ZnEaU8$$J$p<2GBjqg8^l@V zwMvYzAhE<67}Dd$a%u&b0l|3Tf4z^g(opCrgI3>&;f)8bJqV`R_6y0^4qliUk21~l z&~{x*tl+qEb31&Mve>~UG`_1_2<$Zb7IqEk?n%=L?%VcN?wK{TIczwz@_VckPt}p> zJHXq~vxDq~)XsiBc-s-g=i|~);!v>#HtpE49%wD1-x{eu>y2iZ{fwS;e_-bZzhrhc zwtUmU{U@V$BO#cR4%G$bWS4x3v0`@bJKEZhkZ$#!aZ#yQk*hX}8)a3K)xO0I5VSmp zQMTZYKNwd-KZ^G>>zLq?Zl2VXa_VW0qUOV_uL_bF}@^t0<>m}*2(c3;<@t`vZM%? z5JlYgU6(0(f+vsoaL!xxve}BxY(Y?Sy6w6%z-4i_r?Z)7%h_52f2KM858Jk%<=hE*r>$fZ_FR zrriRSLW_He6Npzn1m3IW4LA<-^mT8u@Ynb~T1zQmgLceOmeaP`JxKw~&hV3K=Ao?e zl`@(3a2#Lrv%y~Ap;G*KIsqgCRMoEwUfeipvTfc83!xAze>}^av3>WjTQyLfYj-xg za$o2sNj~Wr)mD92l*D!^tbJ|EJTuk$S)p0v~AU$!yKEh)DM@j1zXyD z$(v-HCdhqx&6~S7z_uIjcTP z=1=1hLJVa|F>^iyZ zY!`3^K>ea5{;P=?R_a~qYle(>iP|;<8;s8fC7H5$kG@%kz{Dz2!k8Vz1C+`_Jozr( z9j8LHe=BUHy;m69e(zLb_ErX^^MPk=?xD`Z822y&$lc*x@v#d1z9itl zzWshJ`Tg>csGjui{USUi@YT}y>)oRF`4~h4-HA)!ZgT_awX1dIV$4GI@NX`_cx$>z zf1d{FWfNC!DQR_fVrX!0`;i)ee^%(y2LG4UAO2ta8g9Y!XYgu8m9M+l6WD1ej1s6M4(Zc|MbVvN2ENj-0CXUn;EIN_mmysV4s`p z-|4KGW=GPXLK{}Ns&L8fv(IBHFj{DXe|AdP&{KfC4V7?3($7vtn&2 zngRUNudYx}bN0IwVB3Wfu8~ID`7&<<5PkIpavOn%wPtIhj}kHQ7U=k;eQ&Ave=&&y zpk|pWl=1O^!%672Qyf&(BBFBNTk%}tl&0r;vnND0L3ucw%>(KGy8pZ=cC~#@lBLne0I)+nLUE` zKh4C(n-J!9mQHtQoT_~cuy3bke~pQ3iF1BW=#u=ty8OzY*HwU9LoFL*&UdAzQaFO0 z-SGj0SDfY6*n~U91Wor&^28jPx+h=H$W+DSn^r=(sKZgwifp)pD5LUJ*I0Y3y-sa3 z2(1ctJf=H^WIeu0l#iy&r8i4b>GL7!BzguCr;AA+8(| zs_vg496pV1V!v^>iA*flxoSA8;V(Te(L5?TA%AJbop4c>WiD|npe1jt!z?=7|Nibb z^P1ziZv#Re;!n-E;7=84e*phV=gRK`>FQ;OaAxlMESDtdrfj$gtiz_*%5^vh;2udg zf7vSXz@5y5kRv|=arp`&G zfNT)|DE6A``_j8$+!7_gx7^+zfD1{|qYB4v``_oGi1=-%czb-Kf6r$)5wgmiYjmkH z`7ema`E~XE1D39Sf!HZ5zYc%bz;jL|vFl{%B=<7-kT&sTWO#D2cN$}N=0 zZHm}HZ(E+Q&_PbAe-36D5Bjg8$D|^zd531fR8~lf|7%{j8*EzlfQ7?1Awg&c6%Wpw z;MeBuQO>7(e*VsNp1@~4NDXbBI;LdvL?^TT7NTDn?0ak}_7!%SL|wceuL~Gr<7EY; zKU0Y%&vJZhtP;@7r{JmA^@MBz-mG4yzL?0Dto-U+)Yl!ae>w5Dmg38EtxLBV8H#Hr zHKwF#dT+7fUY1#DVPj*K^l8~aUPbRZ90!73Z35dA%WSGaVn61KscLGyGPSC9(hy1_d zWQS>nrYtv3f3M3)F4~4tyAj@gM`nn?{$?+T731*n|49?vf|h*qLh(IvEDp(b6Y6=m z8x6o$z4&$oR47B65f38tDg3zZOS)zDbNv3!nmU6`K)W>4tC|J_UpWB zm>g#v)L;JF)%?hB`P}}qxD(f8zAP9no_eNQYBdcQDCILL!T+Pp&-Y5G)`=BTS( zI;>b6e}FIPAjAeCb5ptEdUAG|rPc83`;$6i zPSNcCniUPkSZJzkM;yXmT|%OIFBQz(?uS@Y$(Pk;s9nF5Rya;{nJhQL7zM&U^u%(ptE*Q5@V z_3F=tvOIr0wr9Q44fde7JTmlLN8+w*yEBgU@B$0&}!GV;uA-aTsQ5{$v=w(pTk=j+Ccg#bW* z9uuU${SI*jKdBtgs~BbU{+TJmCrSc1f3(rPPVUn2SB^d7aTEZ}2BBso#p$QT<9j84 zUb)?edSgK@zFa-?R8?_t~}OwLh~9>p_@>o_qA6H-+u$Qx)FTL;lkm{@1rEf0lev`>%@!Yme6l>E8bpdw?%*e!Lt>xYbrt*e-A6NS9lt0TK?r~sUpV*rBRXc~f!6E`qodyf9aA&yaG z^W=ksL4RAV;d{mL-2Lm*f23&yE9`p|VFJf_WreGz^JxaMFip#%J*R}nz!YwtuX79p zCphu&0#oUahqMEmimTWCgJBp0^WMaSC8PTR{)hjB()XY^g>MsaO7%FGBz z`BZz!_kNwz2^4n_*)*m0GS52&K-i+ZZzRbF9*$uEB0LAA_-AH?f3o>)18ba=@cOTI z=ql*?(@7%p`;1We5dHQL`7qy+iYA{Gf|j|t&IR@WU{Tfj2})Tpw|y4o>QPl3nA)48 zm9yk#zUn_46xi;9OR7J2e{~%uEBZ541-|P;8Vo}o{9VA;=AAiBB8mdI^rJ$ao^itz%enM%>$(3&KZfl&-FLD<^Xh-{L1*=9Wn&}sGvc}XZQs2l zF>i@ktmV=~_fNDaU5CQ*&5#=UH^1m9)BHV-Rs9`2X4#i@O|8JvNEr{}`A$V|)W7oB z_5k)HynQR@e>uOA)R0H&vSk*sW1cx7dMsd0S$DcpL`V5^6)mu#6s5+2I_fABf4{qG z>neVqzF#@K-)w>EXn|kP*3aj@_tF|)Gldhw!xrdvo0#dGnI!G_zq+8i$GgsV z;JeSS#xdko34clb!M$kb4fdtD1I!|bvQQtYQ>F>Ke`Q%F^4kfKnH}5w(>-^RpHR2@ zyRT7&URZ1Uz|)C?wEg_N&q~LGcPfbS>;xUDIqXe;QQgiZe@; zCyFv~{G^zV^8EFXPY$PFe!BBcM0c3$;CJuK269 zekjzE7{7oONdi&1xayBguG+WM#$fE~8yBeTodgZsd_L#lH-huc zf3o7Wx96h@#uo4%zBC&)Ld8LFwa{Wzg^1o5(oNU8L!7MsqeW`l5RMBR;59aGD-E|_ zdjTgdY$O7gCp(Fr$<+K{;j8Z+hdv()e_qA=8+1Otm;$0)!80HtLCSr<|9T*}ft}qB z<$K@5!?yxEBr04RPn5+2#45PBX3VgpedPca@@lGV%pgrJFzuv({X@`F$*gBH5{lm*GF)X6mcb=!<9e=)JT*VA zA^M(6SLtdo3@z^480Z#?e|^oik8Ptbm5cX5wCS#>@5iNEe`gbClKICw$IEZLfBD|E zr>+6p|9W#3(r=tR-K(pH&!0s97l#2*Eu~+t*l=#2PgxZ6{n=q}m%+5KzO*#WbB)A5 zTbg)}#X>RvtyZKy-Z0YtOW*U+K|ECn{}eI@_uu;ynNz=aIkz%YiC)J;Y&VQ3R^@Bq z-8VcoieLW0cq4%DHaT)8eUyEBe-irmlHq^mFx=fsKi`V>(gF5$Hp8Hr+XDc7vTf0= zJMjFQJRUb;$G;(p)b79H0SInbcvp2Y{>_l|4wn>KuuT>?a{^?ot07vDrzCH?S3AMY z#;tFWD@GlsH+-9F_jk{(&QX5nmQy+Z^@LiOTCfEdu{7=48K(Rk)n!fIZ)cI&yj@lSoNktn8+6JOwQT)1^# zRqWWdo99dKaaRorxLAS1*y1_~Og&$eAElk83wU#!5;9vBG6!%Trc~uFYTRqDZkom! zzK1DGOhwl9q5t3$gAu$#f5FzT86E&Xhk@2^YGV=QrP1y_>Yem9XEd7k`@OnXPFs43 z{Xa5w!Ne~OBT0F#x$ocazF{r0i(u_-KEoVw^<~o6IO`Mmq5dB~B>edy6)mK{+SJH3 zKlf-g6~o9v=)!XP!e{4~^KLkTVV`O;>aTO$^v5kfn)R2P(EtW_e{+<->Rj5g1)Ke6 zBb;CU*~sowng_U-C`stS*6ug9#%cg~;is>B>F8G5>NnSVPpx>oYVopXwMRp5ye;E3 z=T39Qp9ZeApieyWR3xpgn#3Q*O&lh_l}=xyUjg+>0ppA>1@=s}z)*&+m)5L6odhv1 zIJ{mXdyLP5mg8Sde=VQ0%3T5LhU(zfz|Dx9;?BzO(^S{e0dU(dcb?}>`EkgDfgyJ$ z8Hlu;vdl!XD9dJ)uLhHsXZGW#0sN9?eAzB8j+x9qjjPYca5h4-9Iji^Z@3XZzHzVA z%hu{n2%LXxE#CCqR9@Po^e3@2<%&U@N!#F|p`R-!{;T8uf2;d>+b|m?P_tb1vZ{O& zgdkBHIau&sAc#lN45bC#Qz*O60)WTS*o#}84KmEbFPElWpA|Pk@b2@a371RLCDT7V zVZMXxYO;i!FhpSKtC;d;dB4sW`G2)I(M$I-lxfW-hOabt+NEK zW0CEx8$SU(LBX^+8`20U%0G43hs$#%w7h^tQS9wrl+6Xct0-7991x2A8XoX?5aa`isqX5H zt&OF5WXt`R`@tPlfJBm)a4HA*tYV%Yp8LBU<(fI#H^6)MS3TK&VlX6PPJe!*UoB56 zS~3WDf7_wXaeMna-xmgnCVkt+XX0w1=Fs7U84QMNjAEcg;rRm=6&S{Mh*jVo;0?F1 zSu2;4t9Ch&>cBK_y$ofge1GIQpl`oxkyUy4n}ge~EAVZ!GVJ(#|F|mjR@jPFIOl_9 z=W@+|q%C~?$M>)8yA=UnV6C6Nl7ydnHn_Lcf1Ix~SNWRt@P`>>o^w~8G`#p|OQFaB zT%&_4Z&X?>q<&ZvEx= zTm_L0#w4gjZdMae>GQZBjZQr7`zc6ED`JSRe{fAZXtfBRa; zUrj%*t7uaT0d8Q^G|d|-NeY*Knam#Irikhde{v{1CcnCVue#1rncKr%{yBf>TizBd zh&dkJ$wer`NX5n+UhH1I)zaFqM_Iogp3D8s$yEn0#(pznU|V#`t(O1JaOqI~T(eAJ zcD_j`@!hoiGirXg1&e*Z-x(fDe;FFllfnPlK&JXH4ddQO)m9&**N`I-`T7}j&@abQ z9q5f8=KFm0qG@hdJv~|5bqNi#U+vrN)M;;4yydSojyI}n`CMbr-|5VFU5Y*ZD)S#QH&CR~o3Wjjm9f9)@66j;mQscbv`?{=gx4ts8;c zaM1xi`k)aak=tLebTmuVf5hP-e^#I&q!geOGwtWQ zl6%!Y00ASbb=+=gH0m5Cuk;68W&v07=`4k2`_n%;#j7d$>ivE=&kUs>#Dm$>c7nUN znFMu`I0{ZN%=}&NYHW(`DIfUXIy+V0`a5_f3-62ldcAOc-mprfjZ2(D&&8&GEpY#S zLk_TKMp8#neSZ@#f40f?YXYo{dNZ2U(i1mjK>3_!y0&dQZ)Xt4xYhOjhUp4`^rrAS zjx+Ci0rw98w*T*ZeJ{1k+ zw;U&@caIn|mj3#8Y@9Y#gQYO7Ix;*PcTFy1U?}cCT7o{O4fpRy;?T?wk0z=nf)Uh5 z`~uu7<)ES{1$YD?GK_k~&~*R|mOkFt|A)EvYI0TUwgmr5MZMBD0AU2(r%nXkTLD76 zA-o6S`SlITe|^4V?!EO?9sTWy+>t3VCCplLjQI=Y~rhJm{Sj%xwL>)#Tp|dIl1k8f6@a~^Y&o>>=^XEdd!#gxnN-_ z4Pazoc6$uNWmjm}nS9mK}6+$a#iZuKzJ^ z7e9jEgXw(u>Hy7iz7cQo3>+r#d5K1wT_`Z!NioD`>PKW8mf)!MnWgX@s^<@)n4R&?sfj% zNKj8qd(KbqzMPYM`Kfg^FZ;51Nf+&{^7DZ{^ySz+toHR1J{S3Eo ze|iqB7$NxmGNQeFHud(~(>n^@D|)vJD|yOwU$}~KV_vLYR@wdP^L$X2@=DoedR8BA zIH=Z7lj3p4R!Uly)OuXHlVy8i%-~C_(Q)wQU+jN- zoWCB&N8^+a4PVihz7i+r+;&avh?i!mf9D)@RZQT{SM_IOU3pfJe>)LHld7gFh~s#va!aRhHdatK<0B z*x0h?_oXRshUT9SU!avOy!M#;vMeh>f)ZnsPfAO$sNm?0t^_FZ7_VMUhBiLFe~tRK zy+5f(q5O))|%@c;ZVkj!%Sy>XUJ zz^>@T@>efc+2kKx&3nEs&(G)N!`1%QGuZdf+cxrrPNd5?uH-paI$mvpfA=g>c?YWz zolhgB1=q7clvE7p=42qS*Iac^t1Q--IR@CEVAsAD8lE|%>WyLM)A=ozghs>v1{&i3 zKOWoZ+YNn}KKw9)>l5^iBU$2uz(4REwI9rL zy?Tf*4>9JmH+^G0qwL?|e>(raJ*Hr!$|eYVhyxyrD!=}CiFOcv^#tH?(VXMX4x@z_ zXH+Ub|DC=j8(({C5~Kh~7R$_X(H$siHt2^2RFK4fAcBMQ%62U_&eF_02`U{yX#ob!*pWtP_m6tkY*> zA-!g9VC;uzY5epICOl zcTF%4>^PFrM#(6ZCf6QN>8e+nAHx)Dv%H+R^>Z?bGoPFs3tq1{hN34v&Wgt1_SDR8 zXU;)!fTD|be4$5fHm~0Q(Gacb`40`z=K){6#T1Rh5#Wp6?c;vfvdB7k;{@Hg>DcfA zIICE|uJaJ-e>UZ7xTM>>BOX6Hg0z~tc8~^alKTm?S^+H2;gh0G^vt<29xdTxoJ98( z)CCqdg=DPg-j2~kD6iI|ntva?_kY)8@EfI=?q|K$p^AUo^ZY+~?CI`+%hp|<9f`=X zRq?#P-|r~KMj$P500hgSwxw5aAkL4bnV4~&s{Ms{f3N{3vvh+RGghGHRcAP^`Dw4x2wh}sEkkf*&gq+~@7?~b|GfOKq)$ExHbR!n zyg!uz5WhN?Regf@g3-5=Ai#aJWA7NmGGDE?SBIP=CY`nPou1fztdm&TprAc8|t`7*%@ zGtmxvb#A>`sGwWVySq-GoK%;kr<$B3XhK9q3DY0{ZyZO_?n9-iD$CbG_S&_@^P}V= ze`T8BPF-u&qO-#)36l;@+}?CPFS8>}S0w;RK(@atHPK(a0JCmHvCJ|%+g{lNeGuu2 zMkbvoVLL!a zvv2pCa;yN&Kc_>F7?FU}Q{HK}=tIR^j(MH8RQ1#05oa#kWcJ~Mrm4Rcsy?}&k@N| zTu!K%*rp+$sa{CBT+9ZtahwAU*yD~$;`_`k2^39qmdpar-`ODON1m?TqO!_ewiQ{@ z4wN~$n@87AE0h4Dx@T8iFhkFvx+PYv=$=ca9mOQ#W6_yP`LzJKxo zG$4BxA30c8q}KI7D69@xS#9=1fxT=Lh~>kNIs!#6Y$JGa6-h&~AP>P!Z`D+#Z-B_= z@W5-YMVqv*cdF1dibA7wnVt9Pk7hiQsUB%}&IycL7UXtfpj0ROuG{Qfc;3^cgr2H5 zaG(1fR|-$h63Ip-2^K#2`>k@kK7VcN3b10obn6UWTD7y`!S?>ZW4?dHyMo5hvmFvV z07E?02EB{8uYSvJJ&N~3;LuxdGYY-EM&AN~!g^7l#o!<)%Hskex7g}A3$2AWS%`aZ z^%Of6f^GN7Kd@-dQ*%RMX$|@LHOTV=lFUAzSD$=i*$6i{IDA`Aod#&%W&5u4QnF;SR-4MOXj`!ME^@jDr z#jkH=s=c<-uLqgw3MjKLK7Z?}Ql|h19X!ofkAl@urDr+>)!AD;@4we4m4?c$(xqg>tPp_t|I*}S zpqMfW=zyCj) zUZFDj=w=Ww6qShcGp31Mhl0YT8=S}IW#g%Pys=!o3(HMN<-%Hzt0$tyw&&5_2W9R? ze7FxHU5dI9_U#a?B-O47abJu(h=3;AK8SU_dXiJE?%nh)KAd+yY1`dh|E2jXihiWo z*~!puDV*iCczNf-v47^4<%<^cVMqM;`<31aAfcH-u=`8G0m7=qa1j8c%`5{1WC5Y6 zZ9yOjHVCSkZ>>aj2Wh-~9&hrz1ZFwej)br1)*8!sGT6^07~PByM<;HjpeNzbDkmwR zmOUZB^Ae652olvpBeri}P1Jvg%Oj`_Uh!*dh+8Tu&jgL*DSx98S`k>1;F&FOYiC-J zawW*vcE0+4Z}B+F$={;Mc~Fx6!KWU=-yIxI{%HEItCo88E_Zjt-!>97rELPj9d5`Rsw4E*Zd;^X}mPE2NbJy&h!BY%Ju#A&7-13(&ayqjzy*s=K!_PQ4r z_VU^y-#?oG_G}eJpx%_OYEKw8u?!M${q54SaX}V&@Xlbt=T&j%tA)G zJy@nmsf^o^kL$H+Pp4gT~F_EaFu6yg4vs=86Q^3 ztsuc2Q>$Ly{5o<3&CmGwz~up^UOwpcBk@wP+q0-p;k|ce?*38y|Hv}ShMM)O>G;(c z4M$Q^|9`Fndg+>3m$n~=?g5W0(ckp>zV%aA|6H;z{PX=sU5ae+BA#=UZ{H(QbsS-b z^n>=!@c2r6rG7!fIYiVy^fVvJm20EQ#?f!TKkqgdO{pIc!+d*zernZ;OMkEQQ*dZq zUVmcgYNx3akU92K-B9fjXpKZq(^Ls1Gf{BZGvA9AWg|0(&-=s~N7D?elAX_!d)EPO ziHxUqqS+p0IgXlXU3*>)T^pv!bDDxx!tT&N{R|yN1}6@vYmk1bL2`okG1;E_V=!r< zbCK|jFW3n|m-h9NG<`JFBmoRTxS`Yu4}U68`guq-Mg8cU(rTwj&5OTu6ZkfFo7Z1@ zR(OS4IyZ}@T#^hVHhZP|^6S409`-?9x^HyFI_ilj++TH}f67(9PF{5I_e}KEUv$r< zP!8s<-Vd($>U2U5I{YWT#e!d*-k#jB((U?x_MU2}d_5n-lf0*fa%Z?t!5hmLxqn}m z96j-{F7k>=ETbZ+Z@59iO7kt&b;G#Utieq`PPO0 zd|=->CsmjBVl_ccmyDUKNhi&_O>Qqqyqr^4J%r|$>r2@8{Skh>$J(}SgvS=oABS>> z4F9DstW!w?AtLQ6G56JUHCpJLvVX(Ny7c6E{^UK+K)c1oecCaBoo*^WKp`(OYM^$q z>rrcW>E>SRSaNT;;ed9%cJ;ni&N;?j^WUG#)q^kG>NA#1dy;KK)J--n;w9I)4UZGwB9iEcj%42Z|uqw-jA{dplW5(&neJXW5NTz6ZFP zcdEy1H4O6`m=@XmN!(BI`)@zrK8hpxAJg6^|LcE-pHH~|&)ZD29>30l=egpsb z;a{&J$o(&`f`7it@4rp?`Rea#k>%6>aIWuv1AkunIihuO@_RT>-G8r_zd!%>NwT7A z^|^T`pYgvrlN<5ZkNn$T{Qg__DYBvsYx^%RfB)jYJaE1|PyIZx;S~P06k?4OQ;T!%B6bj-02+3Rg zA9vyoV@X8B7=-+BZ-38U|LxDmb|UZa|1O#^OTfO({-1X^COG9G`Rn|L^_+$K^(T@8S z#7|a!2J!8LobcoCi6Nv4TF}ulI})J{yXFsZJn>9PYQ6b+IAUBe)s`aN_hf6$8kvE+Yoi4`}s2Q)M2%H zeu7c3F@J*K1mZGzR8m1_9$Pfi%;lzbuZu0HT5j_ZkkqgKy{@3JyWK;F0yx_xNNt7o zjXg<%_bmV*^d$xJxBCh?pu3^>i=cd6PXIwx?^x$EF1EBwz4y=ay}A$ef$q`lNW$Qo zZ3(@vrb-(S`E?WnF!1<%vGQgako&tdBwFi-U&o`VmD0iW%lIj-aUPBDV@zpPcHpUCryB)b3XkJgQv&W*$P(rF%h5i-@&qe z4d=ZP5aJ|Y+IeZ&RXmfBI~-lqfY-c{Wavbf*a* zRmOdgfp;tvbbz5~))3^>f1dH}a~K|dfq$ALwU7Pn@0TFSs=2$*-v=kq9abY{b@G8Oz0LSAOQoF6ccr&1`1;2K|Jv!aa?Ckbi;|R-DN3GMtO!WdndE0oyVcCP=e59SOMnZ?WN7upvHERL zDQ@Zq78Q?x4<>IKN9*}h+)dm4+JBt{n$ocGn7wa9DLpc}cuu27PS|fSN#>F7up%l) zH{D~qzZNXRlGV{i1Ojet=^{~?;HT>V8p;Z$c+ep6a^M3S_bmQkQ%K@Ok}xKk#WhY2 zaJW<9b)A+=rOD&WUX`z)45Fvq48!vJv^2vm$sDE`JtDNI`z6q?|aSBclW1lIx;}}oi7RE;7Fu2m;q7goQ z*TxRR;$hXYi>94F>2d&UmKbI*ck5OfaoOGl$P-1{u0McZB8Z=CmzjNLJh`WreVd(; zc3}r`SW+IdyeTkmaU&!R`N%&%WbLgExK4i*#ag3#$UwqvU#Y7JK4Ru(3LKbsAh$;5-iY`vX1iZIRuNQfo8_<%h87cBSc*YW-HSQbywB ziw-BC(@`#lJPPYkzgo|%2n@5WA7f+L$641W$jj^!<(H$#n3P~0$R=xhYkP$;F#E<& z^zCUE>z6RvI2FspLw}={sWnZIAQ+M3a%J{2h~-QYJEs<$B^k?OT*iM8J4&KkFYqv! z>b?NIl50ahOeI9tjkgR>@HvU$OnB@nc|Ql%D2VRW@nIKU6;A{~AogWiBAs9Z1mExX zYJg_-CG27*kk&dWcnlB*IA+>p+tctTv3A534hFz<%~E*{CW)hi<7vl^ckLk zTn@BEfK&Zha2e}?cWWNAw*_f z@}X2f$$x57Sq>8J;WSuOcbva3doy6vy=SSI!>5NFCACv3XSiZFgmwd2i=_I*QnK2T zCRmCfL8Ut*-a`<;d*c3Sb_@%GJgV?HPMT4ZU_5K(eL91$Cl8{vWKX4SaT>g7JEVI` zsWd+r+b$n>FKDSdH9u#!g*E#WSIY{UY98A|eW@3U5uW43DAfnrXJ{)lvt`6WbTfnC{3PIb=7ZG|n>$3LFa;&8IOdpwp* zc1o&|ukuodn>4aM>}66~)aTvg2>oSZ#f+bME&mXf%_^1ymg|R^PduMq3l5~sKa!D? zBYz1DBE_9NvPmw{!PR?_Xh>peu9k4)wXN?xBi>%r%&9U|gx$GmPdrmD)9PzA6!tf9 zoq4>8LY^CwlqvJ``pR6&1~V0@wyhJmFa=i=-6ULx>g7wKP8}wr^DzI@6nr(ZpeWYo zWi~3Px^JeR9`PMP#e1Pr_IuD!cysR6hkx>|&j55>%F8O@z7kOF5q`Qw1oS!_^<9<> z5@YBSU0_-xtk-$00n@fmsod|1GhgQ!^hO^$K++NhKqOOl*!f_%@u~RLU{4Q?Y%C0W zoWuAL@*h}&i;9hDvDk&2kWdTN5&GUfOPs7y)qZ*2TVA=I6ty8(4lDaJ1xPQ$@9PCL8KloZWi7 zXj};2_R(bTgRpXY`|!YCg+Bfq@pql2_0odiIrXU(0A6ARO(jT@x=wk`ojDd6>yupz z&T-p;ij;+s)qQ8Be7ouI9Dg%bFL_%}i#5vve?8xH>)2HSzQ;3UK-hUFIVE=!wQMW>q#Kyb*m=7i|I1 zh(H=0?9jJ}pih)?0DnioI0wUt&n`2{Dn~wy?SWBybQtk&YlhSM`!X-4X`o!DLq{1} zk*B6WdGfy~il|<=QE$Tw@gzs;9u*CRHeuLsFiNpCofMfW_l3xc2Vo<{yZ)vDV4h_W z_^EA);sTR-WPkNmF&+~{_=Az|IT1&RP3MDq4heGuec#`R*WA?{=4$1ebI`e)m-`9q z%MJsUOfH{&w$yM0h}1c!R3>|9y`KgT_WmySy_i`T)5jH_mc?>s**N*Bn)T8NTmYYv z`n_8}kNY_+Z-6kn=Zy4Ove5Mc&!qu9PmeLOj#OepUiQF7}N%)WCf_KzT68exxSe=vbA5#Ff@*!G6X`)Kw| zxl2;n=;?$WVXRarXC3$;wrxAlVb^i=#-S?KI=oW)jY}f07I#B9=>;fq1{~ zcPyv_FEtSu#xgKH?hK6B0TS$P! z>#1ei_KjDa#>}h&PK0MbyjEM++n{fC1$7>{`F}o9c|1d*Epo|wc$J@s)5C*6x7Toj zrzSB!?G5goYc)Y@Kd5yXRP4(eIdLO73)kR?c|(H6LT5xqS!+qs5!G_YawBM`Ml$6{ z3}0vM;~ZC0Z=DhQV7GEeNMJs}$DfVB$vpJ63EhMYzhHTEZmuxBQUBll) ze(ptFhT)*)gYDKdZD!5V?3@G`w~paOe)xCMHM*(K=A;9-6^n<0El8JqDl;qCKupV) zaoivA0#JVFTJd@?K2x0k<2%zkE7wD#hJN|Hwud%N6v@SQ~C zR+`j4z+`aw>=B2qK14LweYuud27i7qEXF2Im8fH&=?t9ft`O{uadDOI< z+P*JrsQ`%whzwU1$uUxhM;=V|1jKbp@1662@y9Vt@cFt*?CN_3A5&UQHQnHiD%fr< z>{q9ADWe?;owN+KX*TCG(SM8qg>9^z8;k6#lzJYLxCDhV<)_O>B1TqInHnTQ{@VQNrMeHRBebJpbBFs`tqbR7;4oyXQZ5w-m<$VjQQ4WW$Y{meHk>N7kBB*<9{<7AJteE$^(lc z`A$fiTu~F|7xr?GhL@%)O_fC++VuBNbgd_%5*qsg9Iu~~;zmo&dcpyp zM25+WIRoYkK3FMsMSrrvAEI@nF>I_DQDiCV$wnc5a*G~Ex8xSjvYSqrT6_xQ9KUXK zV$gyM)-#foKqEW=OjN7mjGf?IWaeNvuV4g^qQj6&v{DQ2De3-fW?PI|_UP^Hb?dVp zQ+B+!*xM417HP%dBLjAO*$hqDt+Ed}iR8~ET+ZHT(H2pwlz&hLibB%;*{tok@{ARl zNQq5MMF|%5w%?&bgrWD9s2Gh{Nzaa^XKs%!_WXITZ?UFHR;MVD7X($@QhFZ*=WRx!h0h2j{dguEg{yW?muWczrOs0bhV%v={I$1K(DL9G z^7?SspABkjq<><=%(IR++D8?Ge(_O8o|;`ly1hh;a3$tL$ohi4lsz^@IdRl2Lgr1l z;V2dC_Z@~pLynLN9QW^np`}_uaHeJVk@=abNR*;W48u;FxJGUD5!b!6JLEy_itqBz zC!^c+D&FGGo9yv{l~=RPQee@826X?4np>xnwS4@Jfg>%(tBG7dJ9oGM8tomR3a;uZEF2;%6) zQKDVarhh%VU+aU!r8$Ob0vUL|-?bHVr@uv;uu9_Oa~Pj*t?6A{5L^&z7^2o5HI=6C zVZZ@KMjZGakBH)W$*;XBBYR6*q8TJp0NuQq#%0z~HZ(mR|kakKyKxF?3!4^MWHtm&xyGG4a6V%K?xGzC?gNZvsq z&#c(ZdVTQmGTb7VcUCq^{B{EYD4(I1H|SP+2(T-`oGdI&-hI4o~0DyVs&sE=Jh zHZFCE{vc%_lLz+%;+48t*Z#yN&y2C^%=Gpg|1ID05Do}#vQOrXjaPFO4H23nhtkRG zTe4MLy{rHZB)&}pXk>^ep_wOdY2p6ls(+vQbqS$B)BQ5|b4cUkG3187jWeEmz9W=H zjHZ`aCs+WW(^Ej8K2hqYpoL)=TKhau3C>I?t9}Gj<9|C(nSk%Gj%+chkH@ z_DH2TSsOF*DN83^p=w;Rbm`LTUIGj=T>^{SA>Tju`#m!d;ii!%RK-Xv+zA1Cm4Cb0 z{I!W?Yql+F2K6iUd5QN*Fh=7O_Fdo8kB{Cu@;Yp1q)D_cmDl$jB=zNfM?gYwcduK{ zJYj5a5Ai?{sN+?ZbI#D8bU{|=fuur7S1(h{)`ULU5R<*GCZ1~3{w$t5Qm3sY;QIMN zn^Mg2p_ZgQpN$#3<%hg$_9Vvd`k+m7+lR_3De%CV?z^YnyO%ft z0JpO=;3E4TOXPM_OuC~CJm|uOd9I_+JCd&yPCQj z+@nhArmHB4empX9!i3Mj2g;8BYRLJiEf`=Cwo$ua1==yvzNuU(t1SDE+9Bf-i$ZcN zHDa3HZd@c|Gtv8-!;ts~%D!*JU+1E{7LR{aHXrea{?;Mq;#uvYRpCf*`X#q0G zdIc9><8`*7Uu6h>s7q)HAbx7zQI*t3$)Fe8u{ON$L?*+f$bImK6=O!OHEV zOSnh=p=MNKb$D;WSVdedwt3j~9b!99{G!2RkRGC&&_6M`s@OnK*NFGqag5^iS_qTk zn{b~UAyHn32x^B~8%Q*J%FIsT)a>#LB}l$Vl0;C>Q7q(55Y{OpTYpPt4bS`i=HSi9 z^0!-4UXo`KUZ{f<#XlxgskWu22j_njYm$_sY%{GR;1O*PES_^q<#&{0=uIrjrL)!Orn}zBO_>67Gv1cro zYa0OEPBPRUS_?sDbbo*F^b9ITjcG`xHp*ph`{&R z&;so$>He(V`sefPuQ*#}v?(C}m8pOUy!E4P5x}_SCtrT|aQE4TF*~F-T97vtin2kb zKFTB^+r9z}sXiuzj#bh986T+!Q`Ap!{RE&h@JqD0cA4E7Zhsx6?-8bldRl7@$)5=zJSO6Ko}&K z2mmNfNTL}6wttLxNWR81M2G82fF%zji0z(OWTVcrBMD>pd;o>xp!>J^s|`5m5{uoL zBGt}0JJ?beLk99>hcgorOI3dbSq^G$G~Y2P^`sMM-yN5+feoMhCJlmbyg$zP7ZF>s z*xgrz<8nd1`D)z>Dm)Fhw>5?fe+hLw4Pzd<*Li-2lYgeA_Ehz4K@ouTJkL!d zu=O6W3=Uk7g-Y3c1+P|sS-7npxu~l8tv|R+iAx}F5{*)@WJOf95%%QKtWl>19wbST z=Qq`8*?*SSrNQ0U2YrrXjP{W`S>2qj$ZUm&POSdy-bu$iZ{BkV99@tGL_tHNC}VpH zQToKqYDtxDUxT``cta_F!a;d+$4tjp?i}?vN!Bx0e#+0pi8sI@Z4dCCK1FaopZ9Lq4~a63-cd}V>ZuOOIC{XR7cw-pJG{0554u}7 zXn*#ih7aRJX)ae2oUKqHWjA;D#kw52!)vfa@r>&UndkZHUnUJfJR>0=ulM@=+{^sb z#5NeN+iVcP-3(g%GRY)R7t87+#tonF3#+xZ}XgyClMQmwX{LV1@!GB&R z6AU2=<#r-+2KtJD6H#}mmI{g!@88Bol=up?d`+{ekeb7Zal8k-9rl9cJ4m@vdqIz~TP;a1SVHv5irXnRj@Zf_OT;K>qwc%Lwr)H@mU549mBA2Ooun0g8y z%2gi76X~!76Q9qQcur^VAKkAQ(|oFFZ6X7J=D1#$yQ9R-meYyT?{nWgwLeULx?F5>d|29HAaYJ`sW6xoep~@~n_~pbWqko=ZpKDHB z&7Wd%<~BjjCIdfCs!v;`J3rN>EXzv($!wo_az;a(6!J^7h(ix7Dklq}AA|9XPz5tq z+kA*0^2~!99zK0~c5gj<#L_C;GDEWyBAl#xjbW#h>tAC~`F>WvnvM7oYB3-P0M%un1!SQ`o*O>&#lc4(3{Z2gc zgpLZ$QtF$Iv*C>4&r%p;Ge#%Mu*Gvup?Di=0F|$Q8ixyG^E%S^9TLwRh=!l;YGBR7 z>4wLubq>yzvj@qe-fo8+0`?sILtpbe4tK*E27TCZ551B}RK(PB@_%4AFqmif1U^Ai zG-@YZ1~;E@-X8ghkE6n{*kX9Xf(@4V@fe>U`q}otBY%FeDcv)YeA~h;IMR5uT)vGY zR6`iJRFq7u&yjgPV}pDY8apCS1xD8``lB@RQ)RB4Y#|n^!Z;i(eHF^LOZai6o^h?n z)sRoL|CoPB0?H|+dViB(RX`Vy%^PBSC`(eg*(-Z=p)kIo@Yx0Zvz(ikwqIh5KgIhG zO7vFS^@if)eMuR?bs=EyuR+M|*<6L~+A8IWf%CTC3%B6BUli;d5h)Ts4Lp{h$-ACU zswU!h6!6w)WaV?RrjPy*NnGak^G?!dfMW#o<}ain+bnI!Y=5WX&s+-TcX%eS@7Ol+ zN3G*>_Ncl;$$NG!To&c55{}$J410K`0#et+iQ;((|$d? zg;35swgzX?g?|vcBa+e+N_!Sg{B&myxjM9`c#=Y=gD8QeSHeIqadt^K=O6lJk7K38 z4}?qnkI51nr7r($E~WMCNy3*Ba6pJljX(x#8SQsi#DZB3sTc z(XZn;<2x33{?**Z18g?MKz7xts4H_^!o%ngf#9QgwSQGsK`KTj*tYLQ^ST7v)z2M$ zEi^Y>=5a77ydhc@(G1Hz9w<~9QspP?!nX$$47~RKG{p(KE75k(?}js4b*ZJg+jb6` z1X`;VGvq+MyO#*I>gHh_j)FHpp~RWyl2MoV??>x}?4G9!f}?mCzAec_u6o^1H8}R_ z6m~&HaDRB~9y+m)P*)F|z?0&!3y(3bT>w`;<91?`1_yYnSONp|N4(h3MJVHqk z+LeSW{y<7n&UGrq1vBc`ZHV74BaK^FJXLQL7&1YnRTtk*<7KHBHHqLa;974T^v-W0 zn}5&3{eH*F*q}Q~1+Q8@8fVTovK}^&U#4zuW*uoLKBAaU5FiX}Xs#;`FDMJ2L#3E( zE$F@F=E)@=b?sM_k8-}Ev8^ZyLUf)Rp+lnP#=4MM@s#H@c%1hYN<-?nl={*dCIRDx z-tT3uT@959fMfDyRuGwEbn^2myXq6zH-AjIw_VvDW6*6fAC1%`+dnbvnHiKlKm^>> z&VU)b;=S?Pruq2?C!}ebGUi2unw5ab^5zHlF%Y1ss^7*Y9V1B+p*ZzkRn=l$Mk=@F zZrbldIb$ZlDfxsk%y^uiJ3M>(dCrxlPWwS9Zv}2Wvgl=XDu2Ql;h@zE60e8th<})z z)AtOEsM|f5gnb(l@G`VE%X(d+OT>Oz?K_dm`Fd=-bkY@CUuk7BL%a2LC3gqbyB%&* zdr33}ERFDHG~Z*Rda#sIbsLe?qX2XIG>$8bVipIM9N?RG4aIDQ252Ko2fQ2f+8Civ z?6W$rz1++-CE>osX)1|V-EI_M7=IR&H2+G)Vtac#dhGaBib&%I`Q>}>oPUP5pnhD2 z4`z1e44g}5$I%{g*WpF`IZl4Etd}rF-#`p}CIfeJ4N+t8*A|aZ&(^4B1uwiEw42##!u#ZiiKcO^eB4irqMg9>(tiryH~O+8 zmguZKsd5CoIA|+&)iY1HNDs7*x8U6T z{BB&&|DD*7y84AvulN4c{}ck-2$k*$6RqwRwf7bhq$;Q9Jfw4?lQ+k5d|Pt5JPn0^ zLFQh($GDlusqxGUwZgn(_o)x(NOe<<(aurs`T{Iuz#&yaaqlO6B_>(goaXtAwR>z_!W#p8bT>=K@v&e0h%)02K_r7GC-TD) zil#tzo&kVCz2>e&+4;N6k1_B%EsMlJAsOF?ajuE6g|rqZoo>*cD*vXx#s7$ZCOjnW zT1X|9h1XFCqit4#wS2v9LHSMZcblWc}rFVhm1CIHw3Q{o8(Fd;PWn#&$RzIKkd z=t&YI_pGj;&nW&lj~?B2rg(jSp7WzUKwOFodk^!du)|uc{mP;lW2Ao_~Vzw;Kyb4%OvTpj?1L=jsrRK zdGDn0q;+qILscq4vOSVd#Dl(OkuDsv@x-^r2!to`UG1FXB)_#@~P06jo1S8+r%LZkJD^^qt<17}MKf6X3DbD1XWW?OfU zmuQL3J|IS>i(iS^)qE_6VV$+*sJ#S5D|t2AyuZdM3YlfK@ihqng-I7eYyBX1EVq;3L>s1=gSivBFJSTWr6vgyDpF=Bu5bkQyk?(H-SI%)YchTkxsO8Z?wVPsom^KU^ zjlO-XI0|8pjd^eC&asFiNcD~z7WA`hiC`jtmqkl5C=|5Xyu<9Oyl+g;B=p)_qM9zX zI}A-=m>2>QF$hllbQgW!fAY;zf&;xmicsN%WdqPdZFe(&dsr60OvLTv0*U?RZs!=Z z9>%pu7gjgms`KVH_FDu`lV}8R8d}F=`~(XZOJr5O`S*f*q)a|Ypnd|{?$O_{*as;i zeMEMDTSJy!!8;l{L@h5{ym0Nri-a9G9O{IYGx$Vf-3DQd_$G$Vht-I1&z9xOFk89| zrh8(7Yd~jzcvwm^T`m*7)w6K&apc4+?ja&jdUR!F4(MB`p&1C76lW$qN?#vn5quzR z+7`e~S!E10%Hms3*g$rkC$OG5+bRe0gwx=3$nM?(z~|D9obyq!Q%=iSVO`~4nA?IWuC3^vi)ewkm>;Da-~AZ3^?REqNo{S-frgES+e*u0K9 zvhJva_cX-d5XJaTgGM2mtGqDs4NEfRh~Lmt2LJ$YRjNH`Vb9w! zL7OCk2Ej`?*)L>!cq88#fN<1%uaZCsOt#>0okHL@{Mr#1m||ZPqD!<+66Qv8Fy(&E zs3p7CJn96~sF`lu_2rto4nlz+vw#Kk(Uv?uPhBvXZdRVzH%an&*WsmxHyEOm^pVYf zwd#ZFdEE+Cj8qmHt_VUns^8AkHdU>Sjh`!*6C1E;hY7;Xn{!h_C`zl<@Dk2PBZSWU z*-u_gEe9U-^)O$XFDZ#!f1f?h40FEY0D%ygu3%!J5W5@Qd(V&LfkQ&7DTwPP8|yzH z={7mHG;xyfYe@cVWkMN8QEV6F?&L6kn#C;8R zT!XFeHQ{kZ?X;x(0pa_7*Kyy5{f>`Vf^VR(cp_}sSipIn08T_f53sYrDh&{N9)$NM zIK1=0-^9W8Fmxc%kscuo%ZD@nxXE0X;zK*&ClPy9Xtiw>_A#Yzp6%g+*cxJgr7|U% zr^epTw9J1pn!bO89CV&zX~na*i$L@?D$uw6`{=tZ6t4@bX#|MeA5oIw+#B~@TaP(B$=!-MDj6@A z(S-!V0B>t^Z4HaE)6@2hDXZdt5NYk|Jzftkt9HyKl@}b&&0rvjE&+nyNgCdJ}GbR>%zRN4a{A z65ETUOclyfbq*rQhyx^EBuKJpbW6*!`H=2VQso;rS{N(^9eO7?SSDl%1tPk32({KA z6dgv|Wo8e{O0BFl-ra6g-S8jfpuOZ-SW?Uom^Iz25a-v~V!`BEOtxf*g=1|^Y#!qJ zq)ZGvZaj`RUPw@*w56|qFMfC!C@z`Xg96`Ayx(!NOmiY5osvb?#f-`n*v*q1KDT%>kx-${2JK0Gj z;7!CpzZxmK40%`ULc41xf7y6Rr~3OH0MeIK*A*9J@0;2az-!xmYJH$X>(?^%!1pESV^uOq zE`f?nQJxK{0#VL?m5a2Cuoo(Em?r0)E)nXyamx1a4qfMZ1g1K^zw?sq)+a!KrBP;} zXxLjNPO!ThJh0bjK6VCqJxnNsKwNkOa;!H3^-L@7E!+xjO>=vf&qRR8Qf9-_p@_(F zyOCwBdGO69@8+r=x{)?Fbk1+B8_anmO5)z2)kfHfJ##P0Sz9QS;>puI`;9NU0n}P6-XH@f~7fyJ*Nf3xXv^!}~svevV9;h!{ zL3yT5qRkPB=tZ16-p^XSmmpTn!Y()gADp3{`dG#Kv^3a=crvQWx5@ySYI2AY2V40B z3Si@3YRd+H83M#Cm1`ZtBqgAt4vS@KqsO(9IF<+LepG2WN7{{sKcb^3&$#J`B8kMp z?nnbzJs6BmOC70>kHZH_yl*`c=R$VR{w= zSE_ctmU#^WirRlikyqsJn=LVdBzn(EA_SF8Rbttatrc_?f!;v=fm&TGxmQBZ4r2S0 z^gtQ7uHE_4c2dSrtA?!W8NeWLk724v5y2ah6yoVco?;Rykd5yu;S9U8LG=xkkWQ`@l{af}Q}kPVSOc)T-YQ<%#DVAJ{ai@k3KRJpA(l*@AGp4l9Ql;cOPBtZGMN3Ypo!V(C8WZ&6K-; zL(IPR=!6Rd6VN8=4z;t8u6^?~A#t-sQ2oOp#@B3uV==2um-I0P9|w+0VyW%+lDTf2 z6hU$E2psbY-YgQlzwZgCu2R(ct?(QiZ77PFh0 zOFa}2_M<%NSlu?t3JXo_8E*&HryIAN*lrbbzXhs+>?cAfdOVS8a1Kp>(R7z= zV>T98Rp1=RZj{+UJll(Hmsg>_JtB4bX|L-5^4C4&ZhTL=4ON2AepPk+v3itsU1oyj$SFfq_@C1LZCR%nL2hOR(wXkB>&2Q*PR` z0}{6w2-$aUj-6KBj19!OX@3T4>b0+Uq1U>xz#P&2^e!*&VlCyknfTk86<2H}t1|9} zlVQ>m069R$zaUKqJR-Affs9(p1@(gOKHt0%(!5mfjJHw~;+dZh74N96o%AnarSU303Dpc3PSl zl$Q#=2UfXspPh?Ij*Tpue`C^wX=aWk64L=K4g7dC$U}2X-^}Q#c|2+jjq25l zgDKca)&v(2hg7(WMA2J1$pkJe1u)>NGqFN!l;+jGx8uZ&@wz72POs*gMQD#0pNRlm zCc3|Us5A(XV?pTFGISwiLw_UQk8Es_YqLopfo--;6Zwk}cnJEc)%^N?e~uSAr3&=L z?}vmen|$FO_GnM?zwk}v7H6owm8d&M^)26l=RqO*J4_;jg2pX68kX0e|rL`t4xwH!0PXGp_K<&2OHQu(D!4es%ABaH2?%gT^Lb% z!MUgOP}-G(+7i>Z2(1!5FZww2h;%ZVeaGiY{e+#1z-jqdeIm+5voh?}F>1#g7-AKwn zslHwo5V{{SLJE+xe-55q7I6?rC4TQdYRlN#bda%y;wJ_=(N%1kakC!kO%#M$0aMgk z@fED%=pNBRvl!j{N{RRx!A;Yi=z2|Wcec*FweEd?<%K71A_9>$^Cf5}M4+O@=O#+< zD-+ve^Epzo;YZ4tn!cHW&Q`WU$Fxwg#LdRt1G%F|c2DT6f8Bl0=xdXB*8xc4LY5Q7 z4VccUuW_y6aI&EluGa(8ViFO)(<=*?5 zd%Jsm;x_i(flL2@!7z|N?lc{b+Ax9|2hrmRQrrFHcZL>Ox22AONe>FG<0ObPhoBS} z)KNjJv1cQ~6LMYG6HL5ZA7sh!ude=xgXehJYCY;d1Go#2zOv|d^KyQkHe?C1L=MXb&WrUCxf>2ez4QRPUxK$0+ zR&p$!5A5MSW`Ace_|cbu@~RK5gH`r%uWrvgP|c;N1n|wA2_J?a-T*=cLOayU@&|hD zGrjGd_3w&HKZmyka@^%qWMwP7hZsN>pEV=iu(ts&uX7T+B)S6*krQV0e(PjaMwB*D ze=DqfdcDjpEogY9g}gK+8+#d;onc$AO=$0h-JfAkQ{dRdA5Wz}NEH7T6ne8_nt?p*o;;AN=g7L1Rz}-*C zf7KalFZHK~21xa5--mj&Cd2`{x1cI5f8{cGIxnk4bQ0F$*NkCV**Dy*rW)qIk@Dm^ z^fqP{z&W}Azz8k#XF6IG7+NthiJIn47{>?Q&4-Hf+ujNfCii8>j9Uq`4i>#}JLzCBA=gpwWI_h^!>K_J}oMO?Dm_|gtHntMavC!SJ=It zgZ_>S;61yy8KH2D1=kAwsh7)Kf)v9B;@Lh^zKxm-iv_cxedJRYpdSJOf60)Y4JI_R zDcDs1zAw)emKItEN&75;en!Zf#A&XEqKqOUT@TSwudsb1Mi;S`e9M z`hhb5NK>}N&b-*Y!Mv?q$aQ_+dR%7fZ!hkj^7=rWYoCg`x8QKjJR|xjmw%jergPH{%-6PK*&;PAfZaanBvj8F{JwvXABy3f zfrC-IqrF3gGsFkBe?e!ye7%BW_3?vF3!{1VlqI`BdsKbU80W*&jQMgVf83t0o0fJB zw%TCr3pgcPJtoxddr-P2xlD$+*Q=@s5VS3#kp~s>HB-4~h(Ll!(St@t3xm7;6nhPH zM`Q1{pRlp;2<ZW;H0gX_j{KWNrxv!rj;Ma9@r^j@D=uKn!8;vLWgyBF7m# zoo)5Poy#n?)uDSjF0f%f?{e(DF6{PUxM}_@$e;tDBS#m&H)ywtVSmm2 zXXSI0czIkcqi%+|tOc=9U)Je1ZKSN}sM7K$Rf?dge?J*1y>%ml9vSwqGB3crxNN{E z!fHYxVzTYFwrjbZeg4FV8&+iKchHm6OTBRK2I_(L=3y;kIZ9(F@O0nwdnQkn#hn<_ z8HUiFrENC0yAfB2w~K)1f^k-#j(tV&cAALfd_EVSAkwS73BgzNkT_|83dYAHl86$@ zjPu=;e`{mh_>N(lDQIdrmHPU@?KjYZ8+g1E`KO6+MQM|*Ke-oWEe?nRe*ItY%KumW zSFpR)Qn}GjCSl2RiiDzAQ9ey?<{l@>!KkW@FxcCxTq-*|_=avr(lNOu#6(=I|5XEW z{#X7R_yaQ^b3r{>Q`Ja>Z2V&@Pbz^!XWJZXe^uOM(dYetRm1M@f0Ns1$jI0vZ)bzZ zBKmzT4~nbw1A*K?a8}ODG09#9Y*yz9=KkC;Iveekujs?)0H8Cn5l|GgK{1tPMB&xh|6DJfWy|>_bKGs>6@G&Hl91n|$(`MwW`XUyeuz%Yz(V@x~l1LLf7!yjm4DtVOKr!?>^|>u_QB&rVpFhAN#!E| zF5G*yO&?o490~w;-VUL|p!lZLYJ1`{Mq+0*B4qd+A-9N|Q!VrRF$PYE44)3`DVe>DoA zhQgTZBl;=sl)c*E{~8<)3&gbpCtCD623HGkUhtzg;`&GoQ54OCJ|TheS0S~;53pc7 z@i4w|@4Qw#A~}F(tKWv1ws>~*YC1xpt#^6kFK8flJSPC$^U92yWEUvWAnM@Hf7PhM zgv4108;b3Rb>%}dd-830cWY;xe}%2WsPymalY7Cs$L5$v2zTchkr5Vtr@uV>hbHte zRDMZL(~Ht#oPB6YypNbJ5?>A1DLL z{8js^u6uI?MjiSFg{q!}P!rVDc3WczdvlNFJiBBcGT*hZL1QVh2#>~Vf8j`CaS~;3 z)Ac_+_6D}+Pg!pXF2IfjpC<_(wHr(Se_Jb=kQ69DK^{Zl*73KcXU~#f#9Uer`=izM zKD0gdPS3k*S%v+^sl-z(Ruv6fmcQTWcz|e}_$MM5Qkeq(;S{0BnmrT5jcNTQNRUY+ zcy1)iIY;SaPHhX-p-`;be=!$x|7;6*_xJT@SsQGsU*zd zPXhvX2N-y(Hl66vCQq_7<6=60Wv3V)y5!yl(XVE#eMpNOxznrvoM%1#EFa?Vd9w{q z4Ar0a>9?>k>aA@-gg$Eh&ZQ_vwSHr~X0<)F?`b!j^nQtw^12g@nN#WqYp)vT`O{Bj*Z|IuG z^KQ(Ou>S0MxK{x$f$Phk(4Owb!lUTT;JN8f9GZpvL|VCc3VFG3`r{eXJ_A}&W6oY!uzwz*OGecjy{Eb4c@`8 zrWMN>AXa8C!)oS1LWO=6$?>so!sTy~Wfj``+2Z^g!1mCSAHwl^4Po;ZxRBVx+H+4N zU=xb2qGwE#BxJ*u&wC(-hi9@WwX6d3smV0y=B6U- zqUo$OTG~ipNu^B~oQK~1RZcH=ngHJatjOoD$hi|cdVl$`&yLrCZSr9;m@(iADL2xM zEBp+++r^H9e^Yl_*oKjl+bHzc0=TJr*^SNo5W3Ir^}NHqBcRij^*-+^ z*~c{P?}i%%UQ5(+tzF+>V+*x+v*yF$h`TEsU;S6_SmRfnc9S_#Cj_MMOnD`wldXyj z929&wU$4pS6$#$@=!6LDi!wbKzhm0(7)EJ{o=#V&s<9?T6J+=K2JlVSx*eLSrqPTK zk9QnTf5rf_lB0Nh{oYPNsXAOT*+uChNIo9j^Dh2TRqazzRGWx@gWSEY|Dzv8+~e1WWP36_=6f?S ze;igO3{T*!KoFr6Q_wxTQ0=BiN9^GPyb)YJ!TtGef=jc<4TB^0y?C&nKCnTHQ?eNw zQM>dmp{duVu9aUp2)cl z3#D+wL4NSCUzEs`B%xS^IljK{S$HY1f4Of7gh2xV4Dz0pANe# z2@Y?oz`Y#fa7^N6{lVx*=vUo{;4tL2g16TBv26^JDpRkJ+dj%0BbD=oK3q-gU_xXnjyJOsSsoD=UX z?5_|pyS+RxBs#wMeU0T857*c@e+aLhD|~0=LK5LZjjlidO*pgpQdnu z<8N*X`DJ^e@GAEdtV6+yZ2WkyfIR1Oy|6xu7CZE1%IYTNe=35(=mTB)?N>3; z<~{Xzo!wEdH$(rA->aJl`03uWTiXeLzVCNaEd_Qhh((mzlGwHQ>)v#*aLPM}!YmZ? z81VIPcM9Ow42M-Dx?_A2#xsknxz&RIss41&R=x~tMok}UKQD_bs_qhw`e_Ab(tu7r~?w#O72SNe*IIJ)H<^|zpw!83a! zaYTJ$*W)JmZcUE~-Dux$_d@L8fb?H=%hek8Q6bk>hLYK@{zFMqqOWN3iSMt$f{DyO zy@kE#>}S1tPal8(CG5Lg06ug8ECd|a$;#d<{u5WuU+mSke=Q0^;pJZg@d^xLq#rK* z>m%0utNGn{YY^9OSHM;y>G8M}S6z|=fByU7!SV+HXC-O2_)Zabd+M69h>S4(p6g5Z z_vPYZgEl}NHxA42UTQhpGt%wUUoM6E%|}Dh5$Lt{`+x@6w!{&#YX}U?wQS4>jhz3( zI}ne2Cjnf?e@Xh)4*^+o?)Q0#Cb6oFw^u()>9>%>=Mh2S368ktHUW@Kg#u?g;7*68 zX9OP}4=;bvNuHZM7v5Z-pQYI+YKyCX4Noi$cGu$Fb+hxHxJw!P*G`+iUAI`AKz zVDE&s%{;hIS?Vqh*kh6;P_I8YRo5uU4K#<1U;dh>aG1a@fb#C~WI2?jY5Xm`;ai1@ znRN~Qf6Or*JR-W|0Hd-hMv)nF_otkG2JiSu{Cl${*F#*dpfc)#Sj_3^%zPSA-Yz}c z=D{e8Xl(u#8UG5I`+Hs@EjEBh+Df56a59=8;`GcRhq`=}ff+nkUUgmO@jBD44)fff z44|*}XUKwBNU|FXJ@g5{ALb`|WSZw@G(sD}f9Fiox@jmLrs&)l)&YyvKJc;+?A9Io z>0$nCE7-+tj5`=X2Kd zagHJ#5kCxg_^nbXA_Gxh)1`!H#f2OPgiKO^GhKPbuxDt09v{ftr&y@~+%9k}p7X!? ze?tGwFK|Y(4|y}`cwSXiNiqjOrAo{t zUuV~)Bq^T|I@KCfX}OPT+?~Jo0_9Y&f7gaf!NR|j>ht-$nF6n(QBk6kA`7G#(o)<_ zr|x6uw{XWE(Y?mj1%%Pt-+bTL_pZeQ-qWo#J#;3_>+%s(5Y$J$YzUhv9{pGk2SuH$ zkht^>-~hF92!myc*c0$&o~HL-HEQiG@lb%mEcEK6JM=UGbGVCxIL{1Hfk=4Ue{QR| zZ8ImwpX;d|(}(G3g|y9QU<{f5n$2cz|Af)qx9S)-@z2BHsZwSV_?>)j>F0Xpvs8G; z^+TqJfr|)+Z_E5MzM^BP)}8+6^Ucn=7sn5x6!4w8z*$WpiGIAC0txo%-r!JnIDGJ7 zJBnss*ZD~_ubU~f#gPVnV49Bye>&a{Wj(V4Kst~gm)B1nX2e`!-O0Nl0Rf=l1;*o6 zde&B6RJSvSbLEj9fGIV=Z%!32;uPn{mJ;1BTAf!1mOh;EYo4o_{k%9<&X-dA^g>hM zT_&c<<}bYf0Z>+^%y=Vf=+}7k&MoBtEFx=WCr1jsP1E^gAB5o!2Rxu&f6fdc%L+uA zWv^;miMh!#1JIKrj4$zIN#Q$&t?g4=jq(OcV!XQPXZroEugv~j4X@jG^v zV{kPLfe$HyaAF2Io2GrPiULu`kzpS!a4q|A5PVV32RpLb{ByMy;55;okroT^u$ORm zKauolITyPG&7fd0X&w44f7U4R2(eFCr^PW2su&LO9qaaPQzS`?u$k*Im}lD=@3!iG z+*`R_p7y;g7g}I|+fWXHTLMf~MnY&k+~&pgS0CxeREhepE{@UYJf9SJ9`w!i;4Reg zcqHh=Q~|8RkI%3@%_ue^2#rtVbb8J3{CM2YZs$gOCSfCnYA)8-$q6c|?@`o}O%h=>!#5d`?{U_+lRA3+!&k0#we+ji70mu=+{z*EI_ zy;$Vw0kB!QV~BY)d#t^mG^Q^5M?&=AC0K6;4sI#*_aUK&m;PF|t*RqSc{n+V9`fXc zP~#DvDVdi?RM$yR%f-&20Ql1f=4_m<-mBcI9z0Y3vd=@;e=+Ko(e34aZ@t%@J1uV0 zwwek6$7o-Z_i@SY2et|je;M(Sm00#&R@29{v12Pgd~Os(r*uv7c70++JnNy;o7L;Y z5|-7|G)`v1`4+`~W}SN9p`dHm81dJq3f|38W(zME1o`pD$Dal-b(Mj*AZWq z&8N0Rl_W1{^+pev@w_0cJ1*UPi!JcISFP~gMy&Uu4crVVq?eGeFcd{`R(Fp3u<}PM zGx@2YR)9!Zuy1VVG2T(pUF|AByW3hDm0S0 zU}z@Bf5=GMmyGLE_dj7FkjC}nzcfbMVS0&+}N}1NM<-YjDUBc|h`4Nxi*Soohoqe-qjd$YY+pYXVo_511n8#U4*8 z1>PAER*MkEWJOLZh_byPylAae<9{m)iSCso;ds}mMC>ovKLmdB=dA< zhW$92Z^v7lNq^^WFqh!p9wV5psNty)UWyZ-ezP1)uTPx{>n(lH>*LuLMxLoEz|Kk4 z_x&f%<99O^1I^lP)sn+y2tIgzs+Y&@6z%Y!5H-RIadR-FG}e z)yw~{xU*0hHbN6sOz||a7SSH>Rf398hB&f@|$A;1_RZj%xGlHRm znjhG^VVZN2uOJ+%#>?CHweb@6fyGi36 zi9Vmh_D})9fJV3GkN4VSN)^QBe*Sb_u9#q$Brbvg|H0|f_=jTveJ^-*S`Gbn@IX@m`T#1w9 z!hgW)nQ0IQTgKaUJ$Ai}!~27j^k+iY!>DW*%X`bb(yN6CJ>O~UZ|6rpGQ`sts`pmo z*?~+`9-B|k()7yj8N}1)N716df7%gIwQZ|#icbJF^4xqY2m&~p{@POO@hikD9s{qJ z!PC$L<+I46h8h@`Ji2a*65ctUN;dv;x}sXDVPe6X;SrD}4%eL)YjXGI4Lu+SBz%GY-KMY3`qu#!C1XMI-PBKOgE}^4Hj+5fEnjijYl(s!xf0NHoPv9^nw`&;&RpBLODC z6zAL!2>>oE<5(6uJEyKlZhHkKD!MqQH7vs=uOHNQG6-uQMaH-tVF z*DF4|mUaPad^lTAe>}DXs#D-hY)$T*&nFt6kCXsd{qR^m+NzV#*y0z)Ma6O#Yp=b$ zaPAV~V6PvT1lhb@@8vBa4>H9iJ9Z^PrZh@u#I#PKJpN6il9xdU+y$O>`h~=Q#OwfY zNnW`XPDxNF>DU||!1iwABc>NRSfHpni{Ll>18jz-%grL5f5KYwz%HY&-vC#7HsVvd zHx8?}jTe8|`kPm}JNv*~vgm4He@OucGtFlJKL`-50d|JNl103->Cb1H4#X549|r^N z-w{}69KTx3m<-0svvQ9twdnkmIDEurP1lsiKNE23%xT`XgD40q08a-xWAZna;l>?3 z31I6!Zk0Rvf9GlFG~&27Eyz0`vsdkXBP&)l4eRFiClaBObDzrhK^M3d;>-$#euNx} z8yGO`t40XA~)intu?2?0JAp+^&AB`Mtwz>yH6rQRm1!B!CaSYPK9wtCpv zzAsZ5ts9ujyv}fNJ^vJE<*Zv^hqE|8;_bHO(Dxw+f6596nE`&wJyGp;r^TridEV=< zjyb5^L$Y6)%`ueRm0qV6>T6sFAz=3!Xbk!b{)v1j(ZNE*JOD^sflVEJvO17Eh5CXM zideBBmh8xVkzoI3VE@j>p1%nn)bl4mrH86EOgve?Oj4Dm%M0dq7hDqRPb)mqOV!#Dida z3F)FU@P));s4BpJet22hv)xiAM=*MH`Z-fP?epYR#0JQnB9UTj_TlL6ayZy(Avj0i z5WBu@X)4YSR$OLT#;YAYAV>~K4Q*Nkc?+)T3Gmm0;5akARNE=Bl)?$Qd@zcemL5Z* zf3gh_rs>UMT8y$(@x125Qog4}>jH!9hF9gdJ%~v=j~kCqcveGP9`ah>IlFsM53vL6 zxF2&7yKXWSnb244863ME3A5uJO9{S3_Rjf9Hq{rUHuKSFtRXM?kHN=I}Y(vuvU5Gr}@z zgoTDIHsapi0r4Zvq#yl`+aOvHV_uPW8Q9fFqN;~ybch^MSMc~fjS%)D#woaWBm zrVpOHg-0UKEOidAnR;7};{*4@tMt5c&4O4*;7iR7!Bi`ke<(5b2-^#g}RbM~2F zD^GdiMtTg60Btv)iRogph)HmjA*6|A8d2b)1i(=#L9OngoYZ}?hCI$;BX#kLh>!VxCIk&Na}=d&%S z1yZFHj<6VxkPCTsxf7Np4HrhAvByIY7q6l$2RSh^9r`ZPv)au7^TwlhY{@fnzPxYC z#rD18&4CwWDCk-L45r^wgV`Jm>3c>T??W%Qdmw-};8{v19rE+1e+mb8BvN|VwXh5f zAs;3Cyo&U7y1sE_D>k*j6^-fo(}ffHnMSvHc*YKXy|$nCgvZfBT5=d@OMWhAWc6=n zD;}l6=&M^-`?A;W_;bktzmDb#Gi1MSYs$1dHfXV*^OsbB_*3v}WoQ_QRpH$6_Ur z9?+;$8||^K0Dr6~1u*YU)gsvNBeKxX&9@X!&67G`ITFN__uX@%neYj0RH#tN{q%(b(2=B{tG&dQ z@~G|eT1LJpA5GvtauuGH%-p#d4^u7q8uRStX^Jaf`Isa738rVnuO-*k&%-s~hiLBD z7%-ksS5OZ#f0XYH>$XY5|I}e+C8vonmw}MPYlw2dR$?(%qFMVG`T^INJ zB-KR+fAlK}0YnNTCCzTP8}e+e&kFv6I&^?0QgK=xakY|Jn=q#YU`zxRQ*s!FRyniO z7_;|JUIN7Y;oX~>r)iWUr(*q>7kXLvGp_`PyD7>WS+D+Qz`QlU=Ck*5togEP=5`2s6UqaW>jxmn0>lybI!!VLKf7pt8y5a!6a6WHPm-doP>a&b)!w77> z;4ju2@P2Gw0k=IUA)#yLKnCTtza4Kx+6}|(U9GF|rr|)TCaR3ByUYdqc8kn)&mEiY3Fi9E%c*xAy4OF?&42N}>V41nRZWeQVY}gB zo4g-KDm%blV8T|ai-wb~0(0-p>xhpnh3SQ<>pxglB!@->rkq8x~*L7Y%M- zA#hT-&wfsJ3$*VYlg?IR*JuZD2=%<8e;!+&1J4(}!(d=-bgmTZ*#*wR<4q3*h^uDk zY=d|~!z)o^5n>fnb)=V8wbgV7qGW*K6L?6 zDQ3go85UrScYshS>blFyPaysj_3iV?UjFp6Cdupo?!d2PciPlc9zE5%lF#$ue_p)91kY6j@JQVo zkI%0CtX%MQM>rn*_^o}i3#Uh)f7^$%J}MW!)O^AxB0<$6OcscL_My}gGvaGpSP64k z5@W1$(sC;dW0C24c;40IFxypgu~|{vj(+QT$gi`)!g0J95!M#7pBGNf-DPHkrfym8FKZj(d-%v zHt^RZ9i2Q)y7M+!1p@|%e|N=pmm+n*m9E@=ju%dzsT?AAl}akHgjje^U$K1e{yh&M zGW#QR9YG54d>*;A_b9cMLkRrCYbK=d0QH?;UR)~h3{m1#fa7lSTj+`$1j}6LMsD;y zU##6&;GB@Kap=DZ>*=4>jb+j_Usm?OIPY;ftIAU(S$l%5gc&?Lf4gQZNxsO4vADH4 z3%U~)`m?ZsMY9e}M5>q$xM|>e>*HHLPI?l!#tEksqHlZyumEgE>$)Z4{j3MzlI^h} z%KoL*FNejbF! zn<*}SS5*F~lO-jY(}!|3o2Lp$ehvJ(ATsw;jsO-&j`-GW0{|4jrz2C0;o`EmIn8(n zmgS9YC7!^CdfqqhA{%ehDL3OB)o1rM-d+E)a|6fFNKOL}e?b`Tf})ZdB}ty8XW%c1 zlai!|`#DuN17iuoxgxxKfxLK1hN|S-ZC$8_Q74Yn6hMLPo_1ZGSdWYXZ<01k5`I6^nN#67C?m|&e9k9J0h~-0? zG)-s&u)*isfAKB|z*}}vT;BW8#ONGx6s%bxs4QcN+ha*5IQ+p$)(_kZi~CJ5US(>V z6bZbN>*F=D9nF()(Dq>*gwi3h2RsWo*d%Z{6X0UwnIu`{{3xds!Ca-_dFZk|;O38f z&)~XyM1B8Ccr0>oKEzD6#?zg`wgr4Gnp4{~GN_F$e@!leOegSM_;5vX)4Daf0R460 zyC@eQi&l_NW2S>Jm3@}v@~Uw$JRaE6e_r&DlBNvJ7fyPAoW^Nlw_H*;z}fN=_LzyM z=k%+Nu7$bmj0Bt!gyCxfhqH^`5)*!m0b)jKufViUpKPQV0G)9a4$~8F7;}8mPv#N7 zGG6KJe?pIrvUsoiz-3tendc_{o0E=N2KI7*8hT(HLe-`RdR-r*#e6j$V7<2UFmQfd z+VsQ_1V@AGA`$+|d?7gpJit=+{t{Gf+V`Sh<%UF4g95O?hkseG<#bfmZS&0sTJld< z2Qc|syt=>&erlAm{p`&6n1JV+ux8rzg>90Kf36qOOy7h9Vp)?pw6*kE!7sXyB1ESn zw3heURaM~?y<)^Dyj)-}iN5H{H`bm&JSp3{Hd61B3^X=`2&n-71o&`rRj)yi;-A_t zJ$&_s-MMhEriD{<)d}{RMG4%8F1zy0Ub<&MVD>2pu$Au!f)e(@jPiMEo^vEgwQ_sp ze`cdUf7MzTrQysVRvwgB4A#i_Cb2~H`SC3VEsfX~xxy{bSm%*&v;n@Ohn6{;1oI?5 z03@G_8PK(jJxtfF+JeD|5${{?%FkTy4_aj7nXm-)T=}viW&V=nL_krQ&{DwLg8Skg zN9K4tQQ57#)*(%jG~Ly}&I@rHfMeYBe}(y6bfkVGWij98UPynyPYC0}wWKTtp@Hq$ zhK-A9$OC3w>L=dr9fw~->*4Ts%tVjgo*%L-mSIkB?U3hvk+1+gTk$(QIAAXo``2O~ za7u)IWqEJFY8RFTz@M`5^N!lZrFYjt8=6xs<(%ZzYJ#PTtTlV*Sdc6{JdcQxs9Zdr% zD0s8Jd;$&+LsB#dEZSlvR)^1ffAeC1$!Mmq?S7-m^9R4YxX&xPluPX)NE8A7me6_q zY1aEu7czbL;#6I4_8h=I3qZ~9cj${JJ0}>x>Cnq{XmI!a#1e*A6R0mkdF-1oX8E>0 zhz@zYUL+}i=*pgyEjo!C@U@n%7H0tYj6lN#r5WK)d|$8jVVhJnydCiPf1RGAF+49X zk7Wfv1=qaTXAmxM_5Yb~F$UNF)FJ75$t4AnZ`+2bFOoe_k0}X+At-d$c%!x|e)yAF zGA>^P*%ziBu|W2bEdou)?dfPTwFmITb0TpQH3woZsfToe$XK9ENYzr zTDjl{baQP>6};kNAD}+je|!S|4?*>Esmewu9zGul{ooyh(?uZ+pFh%8dqEI~Ic^o} zz4JpfAmr-+xG!;2aS)fn67~DqzYDXivTAm>ZEF={%~|T;TUR=QxQ<7KSm=jwJEe9Q z1js;ZNfokm3$TX`)}At|5~Y*RL(6~qpS0P1L;$<%ZO$Cd(gAxRe+(()g|SkizW`hP zpr-l)RGh_dYt#Er@)RiMNZ9uaz%s~jJ-kI;dWnwd`_5Cy5a$B0?7hP%-$I{xNfYv~ zTF*D|qsyHGpT}boO##VPx8pI)4@z}b7(_}g#}({V-DIK^K{$E9`lWo^4ACRg{eD2m z!_~so^LYE7iE|70e*(KL;^V_}76qi~3r(Q*cfD{!L8c=>dOfd@hK)?)NXo`7OV+eZ z@Ped-A~s5cd`vqc>naB^&6+5Ue}HG*X`U_qJq@pI#KjV) z@TuoJJ zf=H@)E+*c#NDlB~8-C_fT)w4cB)^}<5QmP{RV-XthGTtnFEIuIvSE1h4)gY+Nxtdi za=DCW>EWK)e-wX^8u@yqd+(c6)av`B#9>c@cT20xK?jklB8JCLVKWN8t7Y`)?p!4- z9nL8hWO)@}IG*_k*5^+6a-lp<=9p9?rgU)ck>I@i^bTH%y*8XQs#Ckcrm{2^ zaL2F1x8C7O_AnpjtV&*p0L!7&&6l>5xs5qnd<;d-&Q3&5Jr(x{RW$!U8IoqlIz)Vkgq0gz;if|4K z$5Z;NKRZGpw1XO)_joRH3c&grgYnv*UW{EQss7+%>C`KT;h0#?vDt};Sf<3Y0vi1(2p2RD4%p)|f6tJ;alWOUpO^rzlm&aQT(7?y*V7+- zAYysjue0_*C#cZYp~vf ze{YP({Je~PU~KYAo*vHWvb@m81u-p36sxXdO2F=?%d4P4&_KEb$6j4H)(>Bi1TsWy zn0QRZ>8G}gDF13%Xkd*Ib!?9G8!XWwx0hI#AE^F;LxbnJZd;85HvD+hmx&-Wdx5#A zXxd$XBCgn%6g)2e@*g9cmYKh9nJJrZr30`#kcX8)K`L#C z6Ca%cTz~QCItndzeSx76w%kyD^MBwYZP-UFO{!moIwTqn#HZYq^P6bb0}{Mce_-}u zfoTwJF5tVx2yFVe>zVTANjeE3Ek@Jpha|=u!qRb`tV-RoF7F0zddwd_4%3!_CR`Y3Oc(IVfBErV|gO z0<{HXg1r2xd3TJxw;kgj>w|&u@yHFW+L%%ad_Yk~rG5N081)S87g#$nf9?Ye0j&7e zWK;0StqXp7r8TXS(`R^{$x?Si=xdGc`%J{AfVI~m5&XWkw!;1!{=Pn7y&>3bukc33 z80WITn$SwlD;voW8wpzKVi<@fgl?f9&o3dI0mCp0AgKg>#Sn>Pf2M-Wig*3N%;ge#PaxfVR1X*1d75>Y=x85`{h>-E%t}_!i-t zbSi(@4he^&D#v?;>9B|U;YeI^RJ2*(b)MI{s*|CF!3giIIytlFe-z(d!tgyf(nD!} z4Mw#jfB~ND<;J_Y?dUyVCXa6q-68e;F`29R*V4JG#KNCFm|eGXM9onxX1vY5;DW_@ zc2JuD_RYdrtM*hMIN+Mx{C%(3ef-aRjbY#A5o~}>In`}Z`PK}+@15WWW5RzAxdnc1 z33%A$4Ew6S_3Z4*f9!czyL-Mg>YKZg9Pq3~RWz`_NZ=2=sDYcKBZ+57{Z#)7v5coX z)O?#Jr8Jdt9~SED--#{3|J?Vk=5Wyjj1~Hix~fIM!mEh$u(zg#&(_}8Ug}gh*i?Aq zw0zxAzW{V)Ki@DXHS>$?*LN8gfrpv|MAH1K-vHk0>+kg4f8Y6zJ_JWvZr}{00AR=9 zI-RS>15*q``{76$>>ng0@phNwUCShJUQK()m0NFD3xc#unldP6Wf-_P@L7g%fSM@7 z9a(|{D{H@U!gwa`^||9wZXQ@tcH=aa55{_B=h)lz2#iilC=+mPYrMJB-ZK_EA3}P! z&JDfDt$Cg6f6pzc-tYG`A3mRHIM_|fVzJ&wdoQpDhZ}GA7x09n>+uS2YsKRQ^D%@W zEYUcd?hD=c$HG;64PP1D3u*U@2H4KvQ~YW5dHwROrTW?xb1YvDS*qEyBAHJ}z>!9% zfhE=g>rZ5u6S}RrVSbZQLKD?+jv;&E(c1%R0>Ga5f05qY=T&-rX9Mm$+=6p*+}!&; zt55(I1MVGAu-KJQk|SPs>!(h%-|Iw2)tNir+|Q)AIkQW5pHJ8kuNBUh;{wbrgFyT7 z-x~Dae5eeDyW7YG=E=zN32>ey_|)w*2e%}Nu5O3k@%Yh-44{oD91M)EnLS)d_vQC6 zR{N%-e+Az?VAMfG!+VuI%c0RRX&yf{3zP-;B~e<(+*VI(Y&jFmt%@I2tx$lMURZ3c z_lsU{GUWRwd+q|BP>pa~kzI0p8<-hVcP)c5EuW@d1mgsznW1 z=IJ`&Rr9!vU!N^}-?tJ{?J<0##{{sf6K(K(L5c&cx8iB{eOzudO`|yb#_%hNr_!13 ze+|Kbeem<%e>l^{jbzz!06YLqK(fEB9MMF`>{csN>$pXuR$$E~OpG#x!-gOJ>99?5 z9g#o1*q=uV&*B~dAta7c&B-tUTPy1tMIX(NpNmWFn_iO?uwI4|XYT5$=wJ~tCT{rk zoYzwE{E$cN%xZ5g{`N$gG`S(j!)Fc$=aM6Kgnw(~&9TazD>iIrF{5+||n#(d1%Lre&$ba=g|se58z+fwV&+2`DK5)*+v9j_OO z&d~@^rA#p&UFaJ*g}hGK&lgjZ!-B<<4#Fv^hU}vO%zF~hJ&)Z9 z8tjr)XKqjxCaRr6{Lx_L6YBQRr|>Qnw3v~w2S()=lITo!F)t6AnP93XKaa}#vIk13 zDXPh(?)q&F1TpLthp%HlB(t6xqo+RU=YMDFpB;-!PszfI>Ux?0?@3@C7o$%(a*FdU z!`^Qe6NVh0%MFocO%jI!{C}>t1~_11tk^3b^tieTmYMeY6(a4D+>pPWn6f);mJMmv+m}*~2+!)_;Al zO9WcfRYk^acaPiMw|>xSt7+(Lboj&`4$J2?I6cx_|kbuj|(2wQzJ z)jQKiV_XBlEAKp0nhx3}UmYUgzcSx1PPbz)C+|ZqzHqu*NnrC}4{5;F41UTTLj&KY zJBx^`E>+6%WUm%tiXoPL+6$k-$$xS*alHDw*2+)5nMcES=a9YP{PZiw-+tv74dKYk zbBs>}-nKY%ziiv$8kN+F&Bj>n<$|+L+ht&dz(l>A7~i^_ZYmpAB*F6?@{ zY0`9wjYlI?qXs?=mNSDGjK~Nu`HHk`yJ)MW!?znApU((Mq#`zzcJI3oAAg;GaPRyn z|H4NG9Izd9U)>s7t*Lp#aa^QKb!db2I^afG9BIHbU^1 z?lqm6ue__rsZyM8E+o?~5T9}KDSo@KHdDUmXIah(d`cOHEivnScKr-KPsiUHIZ~g3 z@Ob+_`JOj<3CkC^ws3m<%eU@445*XwXCV3lXB30j ze&1tz0Bg@5%XAA~fwAh2R~Wn2Mz>@1N77NJZ({1f!v>)HtN)LNn}4Rpdq3%xD5pT1 z8ma!)GrTwM-4=^uWvJQz(zz+>8tObepeBg3Qy5`Zwz2UB?_;SB4|O3bUxE5zs(&Qx z{_{`IxAh&^eu<6*Q3u>VngmKOz&y~iES1dH_Gew|jI*L|js}I;U&1LtdL91hr3cS; zE1o{o1bY`~^SAcbPk(MG5KaIKx-ZJ|X4w04;VtL&>$68*ac1{JL#d^I+S6Y=!?kK( zINROUj>?Uf`2R>Kko$Y}@4Wz@#n3LkMEs>o@YRO6QFHi@po77aT;075ICDU`%02Uv z|JH4Qb)FX=Y6yM%3;sJx8u&SB*UItvi}d%9_^|VQYXrQ$fPZ=sG85>Z|E^OBpY`^c zxtmR(PTl>j`3HVG1-IP&7kBynomtm(I;A@ny4w$nF+BI5?>v4r6^_f6Q8ejZ{_{?E zjTWWEqRbzEEdVEiIVUA)pp4A7 z2i|dk&3MjNzkd$^X(gF8#q*56wLSL3+6%>b{1aKw{#gtEy(m0qhxM3+?x%lrQGV-~ z^tB9o!Li=^{YS@SujObU_8W&ScozS2KDZ9&gVSlP$f5qv z{pg-q*snKiy`K!U>CgXeZ4l=d9qOO6iKrdqub!Ff{C~Nxv^+x$op-G-S-_PpfRg5opUt{+HA~V!X z=%Dt}wawSn%T-@7e&U2F@A!pOv*Qp9OakJ)L+m|y(-dRF0lb=(UaAah+qPC**rIa= z|BtiMAb+*D2&}Wym7MBY(RA&wRy}v9A&Fwu))Egnk5pnbpq?857!+kfpR?x~cv)q$ zrfr!p2rx>Abu9$M6HLzY3v=2!{nP@$gCJXbM*c7MzN|-HWclu^SboKSv2XTxB$i?+ z_N@wdW2e}Q9X`FGe>3;aT-)-CE!_vV)T(OeqJJPWGUA-f$P*AIPM-aRwLf)YqawMm z;kN(O1CR95DFKfl#`eoanW$WRhz|zFyfu*QxopHvz9MPYrR6kH(3Y)sKZ_T*`3l~O zk~C$&YrbFD(0qtD*Mv)E{iVrRJ(`4f25+Vd^cK^~h37C&*TMZ6{yCp@{Ad^`JO}`y zNq>=V8r%qiB>V4$moVZbKSfH1FFXjx@mLFY%}`$PUze@Yhx6V-t#;feLv=s!v9k@d=IhPIHO2w(cuNAUDS8x_MJTZ%5ZOBDmgNq9?%ZsO z&xSSUIqs|==wa;l{%Qbt+&a0KcD!)z_`d)N>vyzMd(kwQ){ucYN^F#lK@P!Pfj-Pd_&+4Ilqq=hT_`dv4m z1s)cWo0q+T0-_34l6Or5m<+Rl4)qmT3u8jnYl0HYNGrvcMK}X;J!WS{llq*1K0G0$O zQAv}1Rv-w9F?tO``yC45_5l6Rq|$^t@$SATeqGc$#R|DD3Y);{KPQ4lpBRT0BE>d5 ze{xU!rRbr1m<)Y$SfK+!D!j`;SCdY~b(SxWf9T*Ha?7rTwu2VA#ixtLWPkqNZvBo# zU-MOq^9%jmdviF{UoU)5$yQ)Ua^?G11O8~-eP0brsG|ndB;oHgON_V_6;c;QbBmAX z0kElyW#?>O0}7!b&Ri11H{bZiA*l3JulQg;RO#YAtiOW8OBDb>(znO-A-+crP)^EV z&9aUlR9Gx3$_SbX{6f7@!}2(Z{Ypqi`tU@B!7pXZ_pBE{G=l3 zMaHFH`bVC(e(i z)Ml4GB~3fMZH$1CB#LetJX}L|w>@Kc;yA`k)a5ES@#eqi$BG_{W&gxqyKpd0H`dP~ zW&KJh@cd90fgrwZ2Y)h1W6Dr#KrryfGbcr=pifyt<;Gls5<_CPT<*GNlyWNfekvBo zvg{zmYNyQgi}p89H(tuXhifP|(HQ@+w(ePKlAbI=3MEA7JPX617uz^7Z z0~ne)d6&n6SJr#EGV-HUX0f-XF{g9SY`sf^7G92lmkY|lbbsZgGo|i14sc5^b0yOr z4r=m8QM~<05%cq48G*zWW2BF3Nnh%~*i}O19^-wam|QGgRgF@AaQGY`l1_ zy(Ihi*GONRF@Mn%<-L+r7X(ad-|Wk&#y_4dwPYyzw%}LGun-XOTPWlkW!bkth?h-; zoWpRety_gv+<&@WVxd^mzrvT}*W4o>9Qo6B7=p<>?;n`S?b{oJoU#EXhQR%-ac69d zEL9)EN7%wX{B&Z*0!!R0QjTiZW=%t;niHZvs(3`x-HpW68WB zdtig6I-<8;3{{`Y6-Zj{j>RH-<~4M^20M7?r+;so=Y6XWd)KJ}-f5qMclK8`48zJm zaEMujxZZmpX^?u4B#OMhd$y)u-+i0k0I9H=$4BcaU=?adSf5)Y#zJimls!X*E8~}+ zfyC!D&90DeHK}%Cxq>2isCQhj%8Zhv``xJ(e9W0@^D=b968*vlz8~Os!eKp%3{san zPJeLHsY(UXzqsKPI_=w7DqlS*ID#Wy4&Ugbe!shf>pGPDnn)L3ULggumw;H%F}Atc zt(f+lf%?l!`Y@QggVT+{x%6~=(zz!5DFuc`vLYjK1t&^gW+@-p#bSkT{g6=leDxLz z(Hpk_mnnd>;sWv0eQB6fSXf$W?Zx)Tk$*ftD&&QxKS2H@_Nn>#zDAr1Z_S(SY=XRq zQLqqO4X1j~5|sMO*jt|6IyB(b`((OYaWI^#(wAJ(AedYFCa2m#qY&-UMiroSSA2uK z_Z<043k`D(HIBm1M}3UJ*)0v4y-kDe20ec%5ltmQJifO^m|o+ns0?7fa32a`_Ikl@%F0@1Tyv4;Vyp zZ2!8NS;;8$#s|r(B|Gx!Y|+%Vfk5>N%bmvr~k8t?@Q|Q`G2nNoI98e zwZ}jBcGh0xOL|^hDfC_se38PFOusOo(I9xiXVWl(y*l(q`M&6_a$)))1e9VEb$!Cz zPOQX)ppbWWyeOKfj`t_L_f7E2L{UJ?53o`VS3F~i3t=h&746twAW!8yHEqX+>UyN_ zhX5XQD&!VDQ)a!nZhLs}D1S$1EwXAsUqg>X*kpqI+Te|hNDjYqLXfsfd4OJ(ifO3$ z&A0?XXgZAnyv%^piBQcjFmllGWY#>lj9AMQ&MMPyEs^(Qz{`C##Z5X&o4NdK&yRRb z;TOeE?zu<9_!I@ozh1Aj{2U0vX&pCRx1VGiR?h8{|MNaxv6?Uamw))2-*Mgnt;dJ+ zX~aXvADqdOXGWnbkW*`$Um#QxH5|pK*{sJ6V~N=9(OaPD5wA9|ALQt|?n-JB4Ls`4 zlwd?LwOoR_nNUA6R<+eQ&%1>JvgiW;Q5PF^7*?m-Iuz;Vr1Ahb9Sbbio$k6|ge+qi z#*}H2$P%dI{m3PMwts)w4ySqd#_6MBbUncE^8o66091YTiD1UVc*R?jAFU1Qn{OKU$<)T?wtNCt)z^?c+RrH+!HCs>l7bARk>JNm(ik}oo0M^WDg zBJ3^k_9R|IxQ`}i*^jRgzNb5dr&?@{dN7>Hg?~iwhh(2&Rg_4z4#>#qB32<>CM&2~sxL z7;`$<7Gm)_@tGdpxbxW;%t>?w)7)A4(Fdt0m39&$5EL!GtsTw6l0A*$5qs}C?P^tFQhsR%q=m(SNN;6=+Cq#DOeg2aE*v(PhbUCRevCrT4v^eA6K&u67%pHB4!Gcgh(;q<}+YieUZM z6=qA9ihtVu6|-HCLFEv6pUOkqztoT?A$EEbfXszjSt&)B3jBzh1Y# zu%|B=_WwLbq}>yUExX)w>#C*hbHg6N zq0Y49jNjn-m9!7U^c*aJP831RS5cn#`hvbo{F4*@Wv<(fa z9>?b`c+Wdm@~?C3vOxUgNYS|Ho6zg;msR?!h4~r7#5er+bA{jEwunk~n&x)I5`T>2 z{ZlX7a_(AsF`!5ui}cT40Ksg|@3sGz`x5T?^`9ImUgj>YqW3R5s(-CZ9K@qTzNLf_ zO$L5GmoH+~pZo*IxqJ{?pWzK##;aAKME}V{y6Xl#KHVHd+3|_kyU(BU;e_&*77m^+ zEuUQeD!6N@QwhWK0C&X!lK)v(pMQ&|(hI+8STOPxCoQ>tS`GATtPlWaQ}gAby-%HF z2FGURI1HrFLyoF-eC^&Cb;JWKYLcIRf7f2oIA7dtmzR0(@B4Z`ToHcQukP<_1hS=U zcc196&wH)Qf5+ml=S#1UZ|*xVukxQh0Ae?G2-@4W{rfqo_4y*5f0-k1ynmK5DVAY) z5X6-yA#2R_BmU%AG8z;0?bqS>V@s0z_|BJWz4+s^ZReV-a4N% z`%m*RWdHp?N8=bB|M~advLj!xouGfc5%6!H`2Dwj{1l%q zYV5xp{`tiJ^2Bv`nTKWOqdEHhx8~Dj|A(*s+tdE#|9}5qw9Rk#HGcoqB-caUfBg2> zulsdIPJgFRgo0t1_zxtBqW{2R68aB1N8$g-QYgc-h>lR4`m=4Xe}Dh&pWT*T7y7TC zHY&12!nj;4&j{>$gZ8ukV$V$t7yt~*|N#f$6RxZSqVa7=I?4?f3R|BJXR#$-pz z#hV9*=$aFr^|YjfsU`Mg0nIrS?8!YJylqvUtwXN|Yip$jYwnIcoOd7b)^{HZR-LRs zz{;HilztaqR)^7je}7_dTU$Y8O_A}yH_q-;)=Di-rgPo*2V$P-81-}i`z7*=2hS7% zNWnE-K zCEj#HsV_(L_kp^J0q1oEI^nE&i>{c3)civ@U6#DZljmCeJAZg}`WL6{I5x!4PNA{a zb)T)`Um%XkzE<}euW_KY`+&+nv(cQ=(4cH;FEE_MJh8x6a;v5+F3aF zvgugvlK0qptH%<3F}8NjoA|8 z0)7Bxp%fj_V1Jd{E1iw6#c10WynO6I3s^Nd+2t&CRQe$$a5TK8XvWFd_br*=*#hP6 z0y4pny89~2iAai7iN;Amo-|&K>D)BJwq+(;{)j0WPvD|eEGhzVL!LD{rXAH7nMVLN zYj`x??SZ&HunR_?r(yb@hncxFrOZsFBI1S=AhF3knSbOM0|wu#7x>RcAQtdf7=EQv zEodTouORu=aX3ju+0e7$rcNc#ZToWOPeJ$NY5^}NprvePq=FbX<^Z0gC{1UO99>cp zP|KYL7FHBt$*vSWEc~+g0j{8_UALw!Yi>KMc^(H?-J(9xG=kUH&e*+SI>|4>3+NY) zoicN+ihlx+psbq!Ft=S);(0!=Zj75LJWB(sJrJpS&)e^}Fhu~wT5G>-SZd29d%xc( z9|S>uz0a};sk`c%t|&=jz?^|qm*=^i`@W>qYN)Pkiaedp~vp*L|eN@Sy9`k#>jQsk{IPqY_^3uC?wq}A3 zw}^wG@Px+b+}ZoSJW~t1z*^-8PEp%Q<=59BNrkKxxwE>7ndf;zfVQpiPg2%JnXY?T zuYV6u((y&R%#+q7d7>Bm^aHv*LQljV9e_FA*)*^GgJBe?jxFI15b-0Z?L9!`1tJSz zD=&rlvL<;nB)}-}E5V~dVTdm@+=Y3X<9ScIn6FQO1+ZQx5g(bvdr3y~iKnd1r~t*E z6dcij;O;Com@gGY2j@U&tR2>`o5yP4sec*Yf1ej=Z6dJv!XO>ZtWOUOt|-34Uy-VcR0T5mnp~j ziBUnqMjrS}9=nsmQ4k1Et{X{`P}T}l?>%`bt%V>?7!`?NRL=nv4u5!H z^`1^}o?|qQ$GIGE7~z`OMBX5>lF;ES6vjk^a|@B@iG)ighUB*rHlSZGuN?EcP$X>O zvq$U~NvA3XV~wT36Whnvl;`F(#ItMMyJ(w-Z0IFovj{x7ps1>*FIv8WbnM6}E@%`l6{9=%E#$>9+*6c~L8f41@3!l#KyjD2l$>?_ zvUQG6HSM*mJ+b(C^3u;{Zw6e7c^Ws(y(ewAST7FfK#cHa=m=hbIZ94DU4LHpP*0N& zbe;56UMo8jr6u41L6R4*E)aye7kgV+VLg$1g>)nZC`Z*cB7n#fs4u2#Wdwvb9--TCESkO(@M++eL@e`#0ilc*x;U{VHHW~da zQrFdW@}RT;-p!}%N;YLvUsVD`#W00hA`m%)CkV-mTX2uV=;pW_0kYkSmu%VvF&KcH zQJSaKL4^LO-i%*Ms=D9)Vy?DNywK?WyduCgZl&>Rue>=o<{=di%75inM0~rssivbS zp{`{m4_q|K1#qYD%&DSbgxwk)IT>uBc7#~?IPrrY;{?oaaS}_I)=mKs5J=$lJ*&qF z!qnR<;D*Vgf)v0tFOBVSMPWZsdUKaI)G+Lj{?0OI?n%-eVa6R>ALiwW3ZQd`EmPFpFJD9Rl}srJFiM!m zd1}^;R>?WqQO4=A6yN-gTW6^S7#ai^gHAqmx#`pxZxx8YK!DB9v{dQpDEO$(jRsw} zI7@m>Ep2O@C9{v^3|z2vHCfKnYX!Gf7ckxF7Io*^bANa{V1+Q)3(9B;Ki8sia#bU- zd8cyi7RL>6zHw2I@IYQ}EpZ7d@*3+V#P*mHEVynOuO(td4aPTpd-+k_NN5Lu$KuzR%r@}^$ZkT-q{&Kdvc}xY6 zVghoz<4ArSFfjZ}Am5!T7N=7RzFt|8I8GZ#h;_F04 zdr+Na^PgzlL*Ms+Jax;v8W@-hV}ac^CEh*pRDa5#!4VNatP_;Z+q!&*((Y`8rTdvX z%@KxtnON_$jenTp=g|=TqN(a<>+>;}WKCN)eBsa)gyuC6D)gB4`O6)0NAOYw2T5l+XQzvpkmojN-SYP_?R7&L66hSW1>0FrasW)W4R5JpOVxf;t~nU z&~LTg(WNysVu-){PfXe;Zkt_GW#_6&sL4?76T%(@!5ydI?Q^Z4{fiYfm(C}}bug)o zDOfYSl03qJgz==W;YO14?4kM;=da+|$bWKoJYoB*_<2|!Y>DmEw}j4|U|#-`7#F}A zdrGVy5GbeJx!YkQA>JJml{g8_(=Y%kIUeuD>vX#iz0q*v_lr6Nt(OK=eG6cufog!a zdL(FgJ&d>LPeG6;XUC>|U><8fVvyeN$#1r`a6RDz(E)Muom6K>Dq87uv0~^-6Mq^x zK%X7cXfwQs$>-P<&BGR_W|SDWCDhYAWIgsWATIx0$~tTtmsv{ab0U#>l;AkE5c6TQ zJ;(!(&(l7MEZAygfLV-!AAacqFXz*5xzREy26=B`D+8Mj%DU%#$o&wXi|q;o)f%*9 zg1xP(d*<6n}-DKLC8b!WV&Tp%(zPE|p>8vtNvWC>px}Nvkx6 zcA)R6*pv6Z_(&No!z#1(rn5V{oox`WO(i2-1^Slf36=kbaKC18`K@HP*pM*pJ+xB< z+OykOEI7prQLEHxc2u3BaDCWttruZe_$xkVapncez6HSPa)klH z?##oh%F0Pu5nQDaQM&aFcad(I&1A8-V0bq6uI*CUOE|uaAobo^x*{k@wiZGo z*H{@5WtCToZ+z>u*Xac)9#vaC3XR|PrJ!NnT5iwaqa@Et+R32v!u zce3TFJX{p$b;G?dg(euG6{-&!7p6WKS9dRaaF5+C%CQhGAAdjv2+q?fI_aUul8ENn zCg+zKy&SuGm|*Zq7D;1-H?UCB70h9Zzx<>aO38aDU7kPd-VLsokt-UrO&=i!EB&l4dcT%7>y?$kmGIR!#Da;k=OiFc4FW+lb zVX{{W#xv=1bbks@Dh@vlHt2H571?qK>cAUI*P)N;P;sl(P4ku1n+p*3_hdZqb4s~% zK6WT$Fz?M(#12xjma}5;@;RiOrdhJy61ic4&KxwM3agwre*fVN;|jW;fkQOuRc8lS({S` zrDKec44gm^e1IyjnG~93izpaxN@;>OPk7PGJ+`q-Shv-VlXl47-gQo>)<~)XBnRxF z&d^VJ1qFGm5iz5*^5tF}5aD9!;GYQ=y)?dt-oR5{{B3W=7Fez>>dB+8C#X-~aJhby)Y{$&-VW8)a*>}=MEy;{Z-j2#8O7WF zN!@Oex zYKNU_&v6NkQ%jFr7Ws6VlRA4z;d-RUa>9nlNQm%K(})im%Lyp;8szlfvrL6Pva%R3+*WT{fY@&~S(X zYGz2yEY@GdWiP6!xKN(}R0@44xh-!AcH(iUWGT$5eR!fZTwc|pO4 zSU6M;65vIXX(pq=Bvr_Rs#0|iXC-a%C<8AHd(3Yh&d2SvzBJh=I-E_JZ}LEtSAFrx zd)dboRI0PY14>?DBxZbxKv2o>h3uEt(|;;Ya<2#xBg8!My8aE1q%3>r=<5EU(}@`g zhsZ_JzIxu(x&}gpSXU;pn~wQZY(ipwuyzr+>T?Z2k<~DumtOFB5=azKw#}S+mi53> zVZ#`Y9#qmc)rMOTFfD>mv>lZ&Y;G#ocl(db^u<@l0X^lYDz_~m#k?PssIo7|Tz_(E zuJj}p*Cim$R&DG6++T)^*B`;p_A3xyej#L*S9B~!u>u4^U{@%4DKea?RAts}5!VCl zRTspw&PqY!APBpC>hhCdQ`yD$D?aistETo>e+;9Q1PNF5{ZT*(p>zagMQ^axR^6p* z3m#H%;A&4u@DH82A_b=U5C)1)CV$n1rDh!M*tGAV31Gh3g^03cnG35HLD#~2~5U>3aa4rAZLVl)%-l&DG z5v-`cklq$bbI2m$d!>bEiOY+z#JZROOx8ni14P8x(P%;EBYkSzFD-n{p`)0G$x_r_R%<*%nZ zOw~pahwU*-j#lb57b%ky}}A5=y7YZyBG^?sMZ5 z^?byFt#S$M95PL>TmLvKHh*}GqqD1aNR5x>tyP(?CjJJAFh+ed_RL{nfjy%<%`b-3 zWYbl#l*>kvgs-EM7Q~0DZQ76pFrsKZnI#o%e0tAE*N2IA}F zz{H~Y5WMOG`(n|ZX@9F$WuA+pY&^e7$xKF^qQ!*aj`V;zL(I$58sk7}4*Y!Uc}d{Z zLlWvtpmwr;Vn`JU>o_Kvjh~vA`aKx<=SYZ22BAE;w^!5DLi^ zXU>DWkPG+S#>|vNqJp4;czyR*0_6ukX+5b99pg z!q7`N@t~;a3+o^yh_wCol!|1fBreIHv6}O8vVI4P)IVQ2mbE2^-z;sXNBq?MQet0a zne`G#ZY3p3B7a<%D){t@t|{@?vGHHBpth%IZXWi+rQXn}$)b`C!arTD7>BcmwP>pP znPfY}5yzV!{Dv;k=KJ8N`N9F|MT)D+q~LM-4wnfY)xi%`GD#>>A0#?_KTT1{**L4N zDZidCfycCudl5vH7u*wRl3s<-rf#oL+o1w9tCY5pr++O!R`EFA`DTccw3G7VGw82- zO4BbY7w<$eX?sYL9}NqZbccKT#c&Vw13a{FhWH9i1xvGzHyirJh4(hYwRvuUc+DZ+ z8t|%3;ngX+2F5WP3-_F(^MP|qoAm*Da$=_A()fv5d=>MC3C|wA7=k9&=<=b+l&7|I zF{vO9fPbh`6=Uk3fT0bfluWTW?=Ruv>%?iRD z2#CbcGHpQ567XIiAt|c~?`(LEaaet?0EFnrv441xbL7gA4T)f|IQV|+a0=1)ho)6fL4?yNKSO z$A1!6Tv6&g`)Mcbq_vkWm*1&#Ij~*KksnEF?>t3jhJjpDj|>{#`=Y=KCNu;+DsrWUV%>SSwq2j7=odtoVlaCU|=3qY<^PN0%pM$Sa_G8 zSYD5B;Cp>RtMugKi?8#xrvSAnC79PL#eaGBQxY?#YzS5^Ho$yK~X!RthYj&ysBj?x$S&GC{>%p;DE2)keS-WXRV9KJrd4*0$980Ypxa_aU`%k zqM^jY28qG|0JsK27!3~3fG-pcW0%x>`}q)#!F2xhvQOYsU3)VW(ge!XN#xI>aqN==v(1QnbgFNL-h=ROr6tsfFsD}2#$v@G3W z6%&5(R)p{`hK;^Nb{*Bs!la7OvHJVP5hzOuk-|;Bl0YhGBoM-Zpv(#UTXrJFT(LYd{P!B8XX-s4+O+JA>$VX-zWxHA)#s47nI_fcEag}0=0R4$;RR((ff z=Np!fK#Y^_Nj+Y?zvLWU>leNWF?6+E>9*lc(`apa{o-nz4{Q1HAYWefEdol;1tu3{ zJOh>mz_{jRie-SK94;Gx>ZVQ9Z(0tbdNE;~}B-rjZ;@q0rJ{qpIB(|>-k_jXp;Ic9|V z$j^)0U-&@>mKFdsZ)FFd8$!Sc%cxvM18WV_9aj*mE(UCVWA^2BNbNWHpvgd*4IahK zlc`am3upQiOPSSUs^WqmkkD-F`Qe@mWLKv3;2y=r&eqlggX3u{`I8GSP;^|*T+=R~ zTX`KN3v8@|l4en9=L%VF$FCu|8^?aITgG?g zD9loy`-j1V3y&PraL?zMiUD$oFiYL6@3`pfMpwEnl|p_AKD(9tE~tat9EQntkqxfk z#9vMTjh-eV16wQO7k_wyr{EfqQVa!KNF|Qz5GqU!6W@LIC4VC-lh{}c(lMxz>*07qsg9G4wi2HAfj)65VGywitavE#c+cCJQ2( zE!o}|*QGOw|De@HRVNSnKBW^9NVVK!gHGzR!(e>jArCwNH+x^+eeC3iVP;okeXf1T zCee3k<_?$c_R`PuioCTV4eyt=z7G|4zREMj&Y8DQD1TplQ&KNDg000aA_)&r@L8QM zmLKSxVJV&GC4vVzhD2U0E@P=OaGGtX^|iA{hC`c4zCb?JhLdWw2zPf7K^_r6)h4)} zOG;Ae`cqGyTmn|P#CJm zj?d+bqJMq)RM*+Zp`M+S%3mc?A4etTG?vVxE>DF;#Znqc18=+paL`77)-iQ{EC#!& zp^NI&1uUqqI%}qGkJD?Yfwyub^@Xq-39y`Z9II>BU?Awhljcu?>PJeGpfZjg|_;m02zL6#r>u~O|DT?K4 z&m*}-9Smmd6t(nCZ+Jn~Fd}Qb*#l0siR!w83oIC{)o6DJE(v~`X*C6E6wt?8g;=1S z-e4&Va6(5J?n)TV)ydN_M4f6_nH6qfkCZAL3M@H#D`jPW7v|?I8;S_hmW{1+&>N;x z!+&0+62Bs=!!3>25Z?-(JrvFc!en^!`jl(?aRoXtAppt;rjVv~cF&+^>EB}ivQ$6r zogRxkJjFPjs{sb`o*syri6f9)BI{{aqpBKRUAer5qEmS3O+QgJt({?Gl{dcmQ^DtS6#(-;t#Bu(iL{>VqUI)#CCUR z5o+d;YN<=S$Ri+>MA zHDE(8D~flWqK-ZU8$wb~jk^LBIa65Jueq)nhKGe{eY!7MYk7Jfc2Fb2W?-lTjd1Cy zkqniB`7V3yr`=*=uW%QaUJ&--P0^l;s*DpmY=p|;GnQZP#9b)IUeYswJ&mIL2gF21 zlD>{v&KjnkNIMSVVMng;j>kST!heR@#Rp}+BpCyB7+64?B=;QOZO5Uwq|z0Vy2Z~A zPU2qrnxRL<&&#&Lb=|M8lTwG!b8U1E)-mM_8va~EyN0PH&Pk%TvA2)srt56zdDwO% zmVSEqL3$Pva|5;*fC@5Ekx6Kt18{tV8G(TM1_$1%fhicL@V$;ReRdd7{h3a))j9J@U4MYOxqmWgMxRg zs7b#bmGqpBfMV<`SgUN@zt2y64!+rmLVadXA3#88|M36DxR9b59j;CFBL3B<9@{IQ zl~aHUfa!aUZC+bGKCC-9P=8ZelqeaF9~y;H^W#a{(Yl(d60o!te^otGVrhJgp{;N& zt5h2_5U*k+T0UC#omGnUy1TmCRg!gv0P3sdd$cBOLI0Q`NTHYh<5FhR~l|C?_~d-Krwbx$N@kM_tpX^ncEIpG?olL|;ew zUiTGH9gj_CkGkV^=XdH`XvQnJQ-+#W@Z+E2vYKWV@CA}3oZVNAx;KQyt7_)F`1SU{ z{xSt?e#c5aCj$7)&es`+j8Qxfe|Eg9>bx6h?T6eb7csB*5bxaiTkf_G#UuWj4>v|} zs#sA(o93GXRAB$3yyq6|ycu86o-9yb zr$s+TiU;Ny&F__6^UB&Quw#sb!8iW@zy4o-MXHi*IE&LA-hWz6S^M|6tN(|u3MM{@ zBYMaW<&l0q7bff5?iTo)MB0GH=N2$0_Cnk;X+9A5;c_N{TRNnMvtu+su%Ez044Zrl z5|n=8axC%1!;QZj;1`Z?0)m2z;E9O?FDv|_?1O!7{8ZLcN76zdXl%zC(!(k)%yav$ zphvDBD^5s&%6~zyko5Kp9$d#>kt#g9!`>gzUAPd{w-@v)Z~H+!zT7<|Kd7Qo#{wxE zcCN_ijV(u^YVO2LjOAr#Pw8D)NoY@x<}nCj8LkDiccuzOqJo{DXIqlw`MwRC%U5lJ zQ+47boAUO}-bmA(;GQ@hRIRUGn5O1goK%gpu7%`5)PJ8JpYXY06!lq9W!uhf>9hu4 z-UOad^>&(TK<=pYZ_wZWRL1sw}0 z8W_AINp6uMOb;sx$j$f^M$9n41t16oD{{k^>z1R%G#Q|~E-O0o|>moNg zU%GW3N^EkTneiQllf|jUEiy9>!!6%knGTy+hGpwmeGt}yIS{zhfs4&}e4t^7Yb7w8E#z!}Fn8NX;A`<5+pxTc=k%0%1fM+DA}W z8lzL@J~!-8HsBitUs3-T0Y_Hiys9Lf3#-@}s}-N1c?q)Z{Ze6Ut)?eA)ncsYb*~fS zLNB3bE$%EXa;t`qXQ5#Y=#S%HHZoe0ck}jHZNQh`Ox)*9>b%L*F`Mg*YD_*#|9^E) z)Md}iWk){#?E+hQRLm%HkX-*NBx4n}S6O%AG>lc^1J@19FP#1wbfg?!(KFHX^q*}PZW zY5=o}v-+P6sSk>an(0=ZWbd|$bARRuubgAQ`MU@UbY$N!`)L38`pTQ{_D`0V2RyQ( zV6u#HxiEH|fH$5wOc2yx+aJEKIXZX_JJ{9I?$uqO$xaY65qq9PUJ+Za=kLFY9EjUv zSj9Hhau0lfGCE=$w2KkQJvYu5~`^v;>?UA(PNz{Er@MbPC_ zpv-q?lFG9nxR5Xu$VSjQ545f}4cf=o;*CPBJmDaCRHN?wV3?8;|=`3ubw0>q4 zNq&jTpCy7q!+x8;cFe(wis!jE!8iVL)bGHT8Z!llw*J0T_>_Q`{GLDkL0T}_F>GFbl_OjQVGh^y9@%~>O@7y;((|@RA@heyf|M->3 zDPWC9SlbXDV>mpa)78_#&?1~BxN;50Pz$xcMKV725PB)UyxC_(URTdMO^i3nFsy>m}tkpUFWX}xXMOvUZZl|2;i zzrL@N25e{nG09GM$FqUkn6K9rEG?%-<*!&S?0@gcFIMq-`4i`&E^3$i zfXQ0^V+YbAumMk0=qTD33)lg-4CtwhD)sO6m7uSXp5FE|oP89coc&#|@F_S;{XTC^ zFY>mkT3T}LqW_c^Owr=?j(q_9A8^q~oszumbX;S)syqMrvGXSnG15H~#BcS&n}1~?=lWlP)lZDqRe1lkt#7?>1mN5k4quRvy&1;;oDbq@I(w~x^L`rZ zN6{b_ylSKlNQ%t_@_M~k#_tG2T?H$DC2f%e>hzb0gU`7QbH9rW9L%0Pf*?4^L4Xl` z06;*$zel?|*wZ{{Q9Y_o|E-t6pW)f4EBifD+=#_*M#{UNYd=KY?D zEkO=W)p%O&yeW6NeGfW3OIg^&Y^$4 z!vQ`}9G#`@_1^J!Y&al)YiVGv0d0&1k@MmLS zM_`CQI13IE1D{7R!&?xKI(z*;GAV*(zW)z{cJb@UEZ z`RNd8aRn^s6hHFirkR%8@1KFeQ*1Oh^U|UBps&t>n*S?&iwZa36W5U#YV|g_t^>b5 z6Z0i4y&h$%YkvBBn_$v>fc?%BQNMPQVBc5q=@jc@D!t;FGXNCS62^Y&n_ZGYS zhVi{;Ao5<;;L`SHw&D*M=*QB z@rx6=1YlZaqN#WA4R-byZH zvhxF`7dke~`j0BO`;C=DM?Edx%zyl>v)zH4PCj}Gr? z47Fag&gJA(q>l-8gSCY-Lg|j+Ypk{3Ps{sy&RyJluNZ!!)@nL-=jRuf313`x*Ry|c zFLP%&(%uoAr?w{<;kk9_K$ebNz?^XIM#G@Aehwlu-3+c@9z~S=sy|8dqY9+U%%|TK6DwXTzxeP z+`BKb|0;k3OzyxQ8!TMbf%UCBAdG*CZCZfog?~h3yutCo&+Nx;V2+J8aP!N%Vyrwb zt5bDfA!~QIz|Uc?&d{jf;NV|Bo7`KYE2Pyy%Pk`H7$=ShqKP_LZ)9k9a zpS1&U%6|(Gr7(73q4jF2FjqN=jUqIcsxWj<;{6w+5pW>fbIR(gt~-XWHd251)@#4| zvmS5EP|f((XQI3e7vq0LKO-05B`+Nf>T!U=GOLj0?Qe{$FcZc?A3Y%aj}QC&8F_=( zdh7+_UV~p7GbH}m$B0(}o-N|Lu423FTtLXVBe(VlHtfHj5f+Gf;|OYEJRJwsvd}Mi zjT+P+#V0;lzUOxFsfO=WnM;3AuBi@K|NrD1F z0xoZB+{l08CYXRS;`)VAw8TCh zS&72IKrW8A-Rt}+bFN!%hN}{LPq6X_N8U`6-MB|OhimjS!@s%LXV^inL0c2eF3U3K zg12yX`v%L4KRI4?^KWpJdWLh-!Nx&QJXE^N38D|U%&PtwsDQyC4bQRM+80Wx3e=^r zlS6Dck94|*mhXS_x4&_X41DqhiYrMbVeQX*7D8Q&N9IiUW6tboZx2`=yWRA^XEgfc zOGXajYI_OBRBm-g8`D=t9yvJ@r7>Lob_!I*ey~GA!#(S{;~mB0m9U_0$W2dWOY+An zO(b9kHoZd1PeM&6*Of{yAG~|wQqBngK_Y<70km;vUK4-2g|QJCvR5t(XRhldxOS)M zdVWcRT#m=H`imrXc5YQ(sXfRJfxQ$LG(?x?r4H_uqEk0M0)MSDk``7z{9gk$- za68|j0%s`Ya)aNcM@?dsiTuImlv!G7Q$i7{cJo@0Ap=JiN&5r~hA`s>(n2TKN?2 zcVk@leaAceT z_s3@`ZsMGcZsyVA;*F{P!p7<5pCv*&E<854Y8V%9zAP8{psdHuc#3r3-9126wT{Gw5JO$H? z$Q!;5ven%x?A+GA(YxJe-SWGt#geoYmoA*_wrLQ>bvNWW=)mQ_z*crM$sDrs{eDlv zy0fKhM{vj>1Kbz#iex)5J+w_8t_9Z| zoPS=l?JP;yCr#7X3T2kM>x|O_rWyp<@4(|N3tK{ss8^W=kWF$EL~898SL?<0n5k@T)K|;qiz`F>H<= za|}RzlTXCCp&!#Eh$6F}jrVoa1LA~MJU7s5-{@EOfR^_Q-%35kYn7ayr2-d>BuO}O z5X%dQW#c1B7L3Sj?{fJJX)b@cTHjGW8crWvlS||Yz2$G`HJju3&W|i|V1M+Y9xTfq z74ey)66)bBh#dsf>`JWS`6RSjXzp&$71dLP{B*wT4e%aJSC+1#_k*Vz6mh)b2+OAY zd8V^8E#A{)aYD)Gt6G*;TcY&QzBbS2IB|U9q3>suU2Y#A2m-e|ApCz;VyJ$L2&z@C zVd$0X%G*40&B%VXbjh7L>DEIbrmKyVyvPdlyPR^O;g8Ux3l;CN`kuupij^iUZqgi%(z2-?S6m_y`_CVMhoBbEVzc@T{ zLiLK%ID%LNfgo*}Wb=PK5>___xJ)7k@+0C2P=&%1$m28Up%DV253bj@()Z-SDlSGl zzKY(b9>YMZXiL^6t|TzWSaPCzU(R*cp3c2`=c@D(f$c={;nBdM7!K5>VNbm8ty7e9 zx0W0IrjiQjahS$&Aq}}BXu2$X0x5|~34ECn2Z@k|lUWkEt_Oc;F?-Kua9-8%QJ+HJ zO|Poa-=E>*exV=q_KdIBYx@Q`;dMMF>|q>V=I}F6V&I$4dBqjo==1G*Ra9+jPw#E- zhfA%R!M)}fEXcMq@Th5AqFi3~#a4Jiuhg%TvC+B}z0UcDyD0FPJ;&hMX!o%PmI0!W z&b*yY!@OY6;dFllyt(JU`Nm^0jZAeXb;-GNFK6vvDjl;FL-6*5>($eH3F&n(FxX@0og6>>e+ z)iV5g4^qPT-f8XK?UiYA>H;p2^Z5H&Q4gUcoLil&BsPB~tumMvKnX~yBL=jFiIMU_|>%yTGo$jRYud-$jv(wkw=2%J~e(w?>knPSFfs=T6C8KJZ zTXWYG0Wg2+x=L}{x_$D*79z1lyw~no=KCljISa!|@{XjoB1y;T{O$zfQ!^$y16&`D z@3Eu|r?rqiapNH_TYM`wUjSS=C12TOndWlSnR~w8b{?Zf?`FQ{HLSVmM=UtaeP@`J zO}mZFcE6UusV2o0Woh;iT;Jg<7^cew@bpv1-A;d_(Z?L~3?f16nQq(IJ4w@(((XOZ zpOcb^Qt313vccBnqmjp)=6CJ$PpbP2&dB4=aWzla)}*_?kI^$?Svs8aj?RFOVX_({ zDc!xBP3}?RjxdR}VHig9W7z;6F}!N?K((Saj1uv=J1yyG3LZpPZmv`nFB^cG1r9dM z)sBCV)+>Oe$8%<9dA_j4e(x|h(fj$ger_rJ*UTS>b6Y&K=0@LB1QD*ppklL7u=jWF z0Y_yRlYmrSIgfCjfkv3Cx8s;}rtvvNo&k+eSQ4FQf>D$<=g!i^+=ozgEW<&$@lD;I z=WTGStu!XB7W+7PkJoeVjGSrlM;!A%xfOpe(n#+1%u-R@X^sXS&qBAv;$d9C#kw9R zIdjvN2JtsZ9?R9U8CG}&+ed3CTO!N0p96Ed?$eZ}f=tCb_cVNzXD*S#2}Xmdd+uDR zrLF7qayPs|mzM9K!V_8;OAVg$?CivrOjo?ErD%;uim2r^DCU;u!`&EW^&OtWUaNo5 z6zOh&m<5}^ zY2wz1c-6nFnd`96&`%^SyVDEN@iP4|{DF2bng5 z4??or42_@-z|JULCK!gGlZPZpXn5QXa=f+(l-d)q2et(FXH5d1i8^&xd)a^8*jBQh zcG6FQjcLRQQ{qu@FFKK4mkIa!{0X?cAl-EDAX_Rw*d30^ z10mKj1uTzzJlG?4Pmr|BLmxiMXC$eOcbt5UPF8TCNU;i|qc-f{wTQG480RI;z(*d> z{4=$23A@7zw!AQAESu1JIhfrNBRtRqFt+#x#+L1o9^y z@OsH8n!=B-r#-h7p!a_)jUQ}xJFt?1)9gE(O^nti-w?-@F1O>#I4Qt~EOOmdz`rc# z8xOZf(IH8d-PS@St`wpr%&@Td=yyT_^Aeq}YNzX_-A9d*6nzF#-kM4&Bok+k#c&K~d!8l?xbO-)JUW>3s8m?r@rP4tst>8&;kb3&_N|9j zMPH|>J{S!Y4_x`wS1se$DpW0 z{cCT?I7-mo)~~(o!8*Fh2kZI{;8{x1Q#^>LXN8|%D~^9FCuI`eVsJc={$iI@S|U($ zufze)chddNAaW&0;v%6*DBh@x8k{=2QYGnCD_-U~<&p*G*Zej{4iIHd{M3>m z$_7PnA&!4vpvLfuz3=m$9o|506~p{K}_4eFJxLx0GeTk#Y4D{FTtYmI%0tl zxtf!F^ZrW1U=?SjMdI{9x$yN#_AmE9b;+Q`E&~;P?`V0F7lt>Z-H?T24hK#|*aktQ zqQGoqzV86kv#EYQFXa1S*G)pp(a83Lj_+fHA!2{YS39F72*N3CtC*J0Wv^S0OIz

%GI{B_t@d$DIr?0@ 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 O05}2w0O{xf0000VHf0w8 diff --git a/toolbox/generateSensitivityFunction.m b/toolbox/generateSensitivityFunction.m index d40d757..bdab4e2 100644 --- a/toolbox/generateSensitivityFunction.m +++ b/toolbox/generateSensitivityFunction.m @@ -84,25 +84,38 @@ % INPUT: t_all - vector of timepoints at which you want to calculate the sensitivities % % OUTPUT: sensitivities - struct that contains the given timepoints, the calculated sensitivities and the intermediate G-matrices + + % TODO: Combine legacy and new computation methods. if ~legacy && method == methodCoded.VDE + if Gmatrices_intermediate_flag + msg = [ + 'Intermediate matrices can not be computed for directional sensitivities.\n', ... + 'Call this function with the parameter (''legacy'', true) instead.']; + error('IFDIFF:Sensitivity:DirectionalIntermediateMatrices', msg); + end + sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, directions_y, directions_p, FDstep); sens = sensObj.eval(t_all); + nPoints = size(sens, 3); + % TODO: For now keep compatibility with inefficient legacy format output. + fieldnames = {'t', 'Gy', 'Gy_intermediate', 'Uy', 'Gp', 'Gp_intermediate', 'Up'}; + sensitivities = generateStructArray(fieldnames, nPoints); if Gy_flag ndirY = size(directions_y, 2); if ndirY == 0; ndirY = dim_y; end + else + ndirY = 0; end - if Gp_flag - ndirP = size(directions_p, 2); - if ndirP == 0; ndirP = dim_p; end - end - for i=1:size(sens, 3) + + for i=1:nPoints if Gy_flag + sensitivities(i).t = t_all(i); sensitivities(i).Gy = sens(:, 1:ndirY, i); end if Gp_flag % Parameter sensitivities are stored after initial value sensitivities (if there are any). - sensitivities(i).Gp = sens(:, (1+ndirY*Gy_flag):end, i); + sensitivities(i).Gp = sens(:, 1+ndirY:end, i); end end return From 7574b3513b24282b7bc847cfec18a4ea6e2f3f99 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 24 Jun 2026 10:40:07 +0200 Subject: [PATCH 16/24] Fix formatting in generateSensitivityFunction --- toolbox/generateSensitivityFunction.m | 306 ++++++++++++++------------ 1 file changed, 161 insertions(+), 145 deletions(-) diff --git a/toolbox/generateSensitivityFunction.m b/toolbox/generateSensitivityFunction.m index bdab4e2..12362cf 100644 --- a/toolbox/generateSensitivityFunction.m +++ b/toolbox/generateSensitivityFunction.m @@ -1,155 +1,171 @@ function sensitivities_function = generateSensitivityFunction(datahandle, sol, varargin) - % sensitivities_function = generateSensitivityFunction(datahandle, sol, varargin) - % - % Generates a function that can take a vector of timepoints and calculates the sensitivities at the given timepoints. - % Here the user can specify his requirements to the generated function. - % The methods possible for the calculation of sensitivities are END_full, END_piecewise or VDE. - % The calculation of the sensitivities at the time point of a switch is only possible using the methods END_piecewise or VDE. - % Therefore we look at the function y(t) as cadlag ("right continuous with left limits") and the calculation is possible using the updates. - % - % INPUT: datahandle - datahandle you get from the integration process with solveODE - % sol - solution object from the integration with solveODE - % varargin - optional specification of certain parameters: - % 'FDstep' - struct that contains the step sizes for calculation of derivatives using finite differences - % 'integrator' - integrator for computing the END and solve the VDE - % 'integrator_options' - integrator options for computing the END and solve the VDE - % 'calcGy' - flag that is true if the sensitivities w.r.t. the initial values should be calculated - % 'calcGp' - flag that is true if the sensitivities w.r.t. the parameters should be calculated - % 'save_intermediates' - flag that is true if the intermediate G-matrices and updates that have been calculated for END_piecewise - % or VDE should be saved for the next function call for computing sensitivities - % 'Gmatrices_intermediate' - flag that is true if the intermediate G-matrices that have been calculated for END_piecewise - % or VDE should be included in the output struct - % 'method' - method that should be used to calculate the sensitivities (you can choose from END_full, - % END_piecewise and VDE) - % 'directions_y' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. y0 if you use END_full or VDE - % 'directions_p' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. p if you use END_full or VDE - % - % OUTPUT: sensitivities_function - function that that can take a vector of timepoints and the struct FDstep with the stepsizes for END - % as inputs and calculates the sensitivities at the given timepoints. - - sensitivities_function = @computeSensitivities; - - generateData(datahandle, sol); - data = datahandle.getData(); - dim_y = data.computeSensitivity.dim_y; - dim_p = data.computeSensitivity.dim_p; - - % default settings - FDstep = olGetOption(varargin, 'FDstep', generateFDstep(dim_y, dim_p)); - integrator = olGetOption(varargin, 'integrator', data.integratorSettings.numericIntegrator); - integrator_options = olGetOption(varargin, 'integrator_options', data.integratorSettings.options); - method = olGetOption(varargin, 'method', 'VDE'); - Gmatrices_intermediate_flag = olGetOption(varargin, 'Gmatrices_intermediate', false); - Gy_flag = olGetOption(varargin, 'calcGy', true); - directions_y = olGetOption(varargin, 'directions_y', []); - Gp_flag = olGetOption(varargin, 'calcGp', true); - directions_p = olGetOption(varargin, 'directions_p', []); - save_intermediates = olGetOption(varargin, 'save_intermediates', true); - legacy = olGetOption(varargin, 'legacy', false); - - methodCoded.END_piecewise = 1; - methodCoded.VDE = 2; - methodCoded.END_full = 3; - - if strcmpi(method, 'END_piecewise'),method = methodCoded.END_piecewise; end - if strcmpi(method, 'VDE'), method = methodCoded.VDE; end - if strcmpi(method, 'END_full'), method = methodCoded.END_full; end - - % switches includes tspan(1) and tspan(end) - switches = data.computeSensitivity.switches_extended; - switches_left = data.computeSensitivity.switches_extended_left; - - tspan = data.SWP_detection.tspan; - - options.FDstep = FDstep; - options.integrator = integrator; - options.integrator_options = integrator_options; - options.method = method; - options.methodCoded = methodCoded; - - Gmatrices_intermediate_template.Gy = {eye(dim_y)}; - Gmatrices_intermediate_template.Uy = {eye(dim_y)}; - Gmatrices_intermediate_template.Gp = {zeros(dim_y, dim_p)}; - Gmatrices_intermediate_template.Up = {zeros(dim_y, dim_p)}; - return - - function sensitivities = computeSensitivities(t_all) - if ~Gy_flag && ~Gp_flag - return; - end - % sensitivities = computeSensitivities(t_all) - % - % Calculates the sensitivities w.r.t. y0 and p at the given timepoints. - % - % INPUT: t_all - vector of timepoints at which you want to calculate the sensitivities - % - % OUTPUT: sensitivities - struct that contains the given timepoints, the calculated sensitivities and the intermediate G-matrices - - - % TODO: Combine legacy and new computation methods. - if ~legacy && method == methodCoded.VDE - if Gmatrices_intermediate_flag - msg = [ - 'Intermediate matrices can not be computed for directional sensitivities.\n', ... - 'Call this function with the parameter (''legacy'', true) instead.']; - error('IFDIFF:Sensitivity:DirectionalIntermediateMatrices', msg); - end - - sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, directions_y, directions_p, FDstep); - sens = sensObj.eval(t_all); - nPoints = size(sens, 3); - % TODO: For now keep compatibility with inefficient legacy format output. - fieldnames = {'t', 'Gy', 'Gy_intermediate', 'Uy', 'Gp', 'Gp_intermediate', 'Up'}; - sensitivities = generateStructArray(fieldnames, nPoints); - if Gy_flag - ndirY = size(directions_y, 2); - if ndirY == 0; ndirY = dim_y; end - else - ndirY = 0; - end - - for i=1:nPoints - if Gy_flag - sensitivities(i).t = t_all(i); - sensitivities(i).Gy = sens(:, 1:ndirY, i); - end - if Gp_flag - % Parameter sensitivities are stored after initial value sensitivities (if there are any). - sensitivities(i).Gp = sens(:, 1+ndirY:end, i); - end - end - return - end - - [t_sort_unique, ~, unique_indices] = unique(t_all); - - if t_sort_unique(1) < tspan(1) || t_sort_unique(end) > tspan(end) - error('Time point is outside of the time interval of the IVP solution.') - end - - config = makeConfig(); - data = datahandle.getData(); - data.caseCtrlif = config.caseCtrlif.computeSensitivities; - datahandle.setData(data); - - Gmatrices_intermediate = Gmatrices_intermediate_template; - - if method == methodCoded.END_full - sensitivities = compute_sensitivity_ENDfull(datahandle, t_sort_unique, sol, FDstep, Gy_flag, Gp_flag, directions_y, directions_p); - sensitivities = sensitivities(unique_indices); - return; - end +% sensitivities_function = generateSensitivityFunction(datahandle, sol, varargin) +% +% Generates a function that can take a vector of timepoints and calculates the sensitivities at the given timepoints. +% Here the user can specify his requirements to the generated function. +% The methods possible for the calculation of sensitivities are END_full, END_piecewise or VDE. +% The calculation of the sensitivities at the time point of a switch is only possible using the methods END_piecewise or VDE. +% Therefore we look at the function y(t) as cadlag ("right continuous with left limits") and the calculation is possible using the updates. +% +% INPUT: datahandle - datahandle you get from the integration process with solveODE +% sol - solution object from the integration with solveODE +% varargin - optional specification of certain parameters: +% 'FDstep' - struct that contains the step sizes for calculation of derivatives using finite differences +% 'integrator' - integrator for computing the END and solve the VDE +% 'integrator_options' - integrator options for computing the END and solve the VDE +% 'calcGy' - flag that is true if the sensitivities w.r.t. the initial values should be calculated +% 'calcGp' - flag that is true if the sensitivities w.r.t. the parameters should be calculated +% 'save_intermediates' - flag that is true if the intermediate G-matrices and updates that have been calculated for END_piecewise +% or VDE should be saved for the next function call for computing sensitivities +% 'Gmatrices_intermediate' - flag that is true if the intermediate G-matrices that have been calculated for END_piecewise +% or VDE should be included in the output struct +% 'method' - method that should be used to calculate the sensitivities (you can choose from END_full, +% END_piecewise and VDE) +% 'directions_y' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. y0 if you use END_full or VDE +% 'directions_p' - matrix that contains the directions in which you want to calculate the sensitivities w.r.t. p if you use END_full or VDE +% +% OUTPUT: sensitivities_function - function that that can take a vector of timepoints and the struct FDstep with the stepsizes for END +% as inputs and calculates the sensitivities at the given timepoints. + +sensitivities_function = @computeSensitivities; + +generateData(datahandle, sol); +data = datahandle.getData(); +dim_y = data.computeSensitivity.dim_y; +dim_p = data.computeSensitivity.dim_p; + +% default settings +FDstep = olGetOption(varargin, 'FDstep', generateFDstep(dim_y, dim_p)); +integrator = olGetOption(varargin, 'integrator', data.integratorSettings.numericIntegrator); +integrator_options = olGetOption(varargin, 'integrator_options', data.integratorSettings.options); +method = olGetOption(varargin, 'method', 'VDE'); +Gmatrices_intermediate_flag = olGetOption(varargin, 'Gmatrices_intermediate', false); +Gy_flag = olGetOption(varargin, 'calcGy', true); +directions_y = olGetOption(varargin, 'directions_y', []); +Gp_flag = olGetOption(varargin, 'calcGp', true); +directions_p = olGetOption(varargin, 'directions_p', []); +save_intermediates = olGetOption(varargin, 'save_intermediates', true); +legacy = olGetOption(varargin, 'legacy', false); + +methodCoded.END_piecewise = 1; +methodCoded.VDE = 2; +methodCoded.END_full = 3; + +if strcmpi(method, 'END_piecewise'),method = methodCoded.END_piecewise; end +if strcmpi(method, 'VDE'), method = methodCoded.VDE; end +if strcmpi(method, 'END_full'), method = methodCoded.END_full; end + +% switches includes tspan(1) and tspan(end) +switches = data.computeSensitivity.switches_extended; +switches_left = data.computeSensitivity.switches_extended_left; + +tspan = data.SWP_detection.tspan; + +methodCoded.END_piecewise = 1; +methodCoded.VDE = 2; +methodCoded.END_full = 3; + +if strcmpi(method, 'END_piecewise'),method = methodCoded.END_piecewise; end +if strcmpi(method, 'VDE'), method = methodCoded.VDE; end +if strcmpi(method, 'END_full'), method = methodCoded.END_full; end + +% switches includes tspan(1) and tspan(end) +switches = data.computeSensitivity.switches_extended; +switches_left = data.computeSensitivity.switches_extended_left; + +tspan = data.SWP_detection.tspan; +dim_y = data.computeSensitivity.dim_y; +dim_p = data.computeSensitivity.dim_p; + +options.FDstep = FDstep; +options.integrator = integrator; +options.integrator_options = integrator_options; +options.method = method; +options.methodCoded = methodCoded; + +Gmatrices_intermediate_template.Gy = {eye(dim_y)}; +Gmatrices_intermediate_template.Uy = {eye(dim_y)}; +Gmatrices_intermediate_template.Gp = {zeros(dim_y, dim_p)}; +Gmatrices_intermediate_template.Up = {zeros(dim_y, dim_p)}; +return + + function sensitivities = computeSensitivities(t_all) + if ~Gy_flag && ~Gp_flag + return; + end + % sensitivities = computeSensitivities(t_all) + % + % Calculates the sensitivities w.r.t. y0 and p at the given timepoints. + % + % INPUT: t_all - vector of timepoints at which you want to calculate the sensitivities + % + % OUTPUT: sensitivities - struct that contains the given timepoints, the calculated sensitivities and the intermediate G-matrices + + + % TODO: Combine legacy and new computation methods. + if ~legacy && method == methodCoded.VDE + if Gmatrices_intermediate_flag + msg = [ + 'Intermediate matrices can not be computed for directional sensitivities.\n', ... + 'Call this function with the parameter (''legacy'', true) instead.']; + error('IFDIFF:Sensitivity:DirectionalIntermediateMatrices', msg); + end + + sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, directions_y, directions_p, FDstep); + sens = sensObj.eval(t_all); + nPoints = size(sens, 3); + % TODO: For now keep compatibility with inefficient legacy format output. + fieldnames = {'t', 'Gy', 'Gy_intermediate', 'Uy', 'Gp', 'Gp_intermediate', 'Up'}; + sensitivities = generateStructArray(fieldnames, nPoints); + if Gy_flag + ndirY = size(directions_y, 2); + if ndirY == 0; ndirY = dim_y; end + else + ndirY = 0; + end + + for i=1:nPoints + if Gy_flag + sensitivities(i).t = t_all(i); + sensitivities(i).Gy = sens(:, 1:ndirY, i); + end + if Gp_flag + % Parameter sensitivities are stored after initial value sensitivities (if there are any). + sensitivities(i).Gp = sens(:, 1+ndirY:end, i); + end + end + return + end + + [t_sort_unique, ~, unique_indices] = unique(t_all); + + if t_sort_unique(1) < tspan(1) || t_sort_unique(end) > tspan(end) + error('Time point is outside of the time interval of the IVP solution.') + end + + config = makeConfig(); + data = datahandle.getData(); + data.caseCtrlif = config.caseCtrlif.computeSensitivities; + datahandle.setData(data); + + Gmatrices_intermediate = Gmatrices_intermediate_template; + + if method == methodCoded.END_full + sensitivities = compute_sensitivity_ENDfull(datahandle, t_sort_unique, sol, FDstep, Gy_flag, Gp_flag, directions_y, directions_p); + sensitivities = sensitivities(unique_indices); + return; + end % VDE and END_piecewise share most of their code for obvious reasons. Only the construction of the intermediate % matrices G(t_s, t) varies. % The unique timepoints are separated into groups according to their model number, that means all time % points that are between the same two switching points are in one group. If one group is empty (so - % no timepoint is given between two switching points), - % the group is left empty and will be skipped in the calculations later. + % no timepoint is given between two switching points), + % the group is left empty and will be skipped in the calculations later. switches_temp = switches; switches_temp(end) = switches_temp(end) + eps(switches_temp(end)); numTimeGroups = length(switches) - 1; timeGroups = cell(1, numTimeGroups); - + for i = 1:length(switches)-1 indices = (t_sort_unique >= switches_temp(i)) & (t_sort_unique < switches_temp(i+1)); timeGroups{i} = t_sort_unique(indices); @@ -162,7 +178,7 @@ % because they are only needed until the last switch before the latest timepoint. t_max = t_sort_unique(end); numModels = find(t_max < switches_temp, 1) - 1; - + % if the method END_full has been chosen before, the data for the sensitivity generation needs to be generated again here. generateData(datahandle, sol); @@ -269,5 +285,5 @@ sensitivitiesOutput = assembleSensitivityOutput(sensData, t_sort_unique, Gy_flag, Gp_flag, []); end sensitivities(:) = sensitivitiesOutput(unique_indices); - end + end end From 354fec3f22a8ccb1a51f0ce3b51f06c475888133 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 24 Jun 2026 12:00:46 +0200 Subject: [PATCH 17/24] Allow passing multiple time points to finite differences --- .../_sensNew/IFDIFFDerivativeFiniteDifferences.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m index b056ddf..6366594 100644 --- a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m +++ b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m @@ -56,9 +56,9 @@ function df = dy(this, t, y, p, v) f0 = this.f(this.datahandle, t, y, p); - dimf = length(f0); + [dimf, nt] = size(f0); nd = size(v, 2); - df = zeros(dimf, nd); + df = zeros(dimf, nd, nt); h = this.hy(y); [v, h, normv, idxNonzero] = this.scaleDirections(y, v, h); @@ -68,16 +68,16 @@ for i=1:length(idxNonzero) fh = this.f(this.datahandle, t, v(:, i), p); - df(:, idxNonzero(i)) = (fh - f0) ./ h(i); + df(:, idxNonzero(i), :) = (fh - f0) ./ h(i); end - df(:, idxNonzero) = df(:, idxNonzero) .* normv(idxNonzero); + df(:, idxNonzero, :) = df(:, idxNonzero, :) .* normv(idxNonzero); end function df = dp(this, t, y, p, v) f0 = this.f(this.datahandle, t, y, p); - dimf = length(f0); + [dimf, nt] = size(f0); nd = size(v, 2); - df = zeros(dimf, nd); + df = zeros(dimf, nd, nt); h = this.hp(p); [v, h, normv, idxNonzero] = this.scaleDirections(p, v, h); @@ -87,9 +87,9 @@ for i=1:length(idxNonzero) fh = this.f(this.datahandle, t, y, v(:, i)); - df(:, idxNonzero(i)) = (fh - f0) ./ h(i); + df(:, idxNonzero(i), :) = (fh - f0) ./ h(i); end - df(:, idxNonzero) = df(:, idxNonzero) .* normv(idxNonzero); + df(:, idxNonzero, :) = df(:, idxNonzero, :) .* normv(idxNonzero); end end From f961ee650d4bf6e65b756fe41f8b462b0ece83df Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Wed, 24 Jun 2026 12:03:15 +0200 Subject: [PATCH 18/24] Add END method for directional sensitivities --- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index e84a94f..0270c27 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -6,6 +6,7 @@ datahandle solution parameters + initialValues tspan switches switchesY @@ -20,18 +21,31 @@ switchingFunctions jumpFunctions fdStep + method + end + + properties (Constant) + METHOD = struct( ... + 'VDE', 1, ... + 'END_piecewise', 2, ... + 'END_full', 3) end methods - function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP, fdStep) + function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP, fdStep, method) + if nargin < 8 + method = 'VDE'; + end + this.datahandle = datahandle; this.solution = sol; data = datahandle.getData(); this.switchingFunctions = data.SWP_detection.switchingFunction; this.jumpFunctions = data.SWP_detection.jumpFunction; + this.initialValues = data.SWP_detection.initialvalues; this.parameters = data.SWP_detection.parameters; - this.dimy = length(data.SWP_detection.initialvalues); + this.dimy = length(this.initialValues); this.dimp = length(this.parameters); this.tspan = data.SWP_detection.tspan; @@ -71,6 +85,8 @@ this.dirP = dirP; this.fdStep = fdStep; + + this.method = this.METHOD.(method); end function sol = solveVde(this, idxModel, tspan, initialValues, nDirY) @@ -82,6 +98,27 @@ sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); end + function sensitivity = solveEnd(this, idxModel, tspan, sensitivity, nDirY) + rhs = getRhsFromModelNum(this.datahandle, idxModel); + + if idxModel == 1 + y0 = this.initialValues; + else + y0 = this.switchesY(:, idxModel - 1); + end + + solve = @(datahandle, t, y0, p) this.integrator( ... + @(t, y) rhs(datahandle, t, y, p), ... + tspan, y0, this.integratorOptions); + evalSol = @(datahandle, t, y0, p) deval(solve(datahandle, t, y0, p), t); + df = IFDIFFDerivativeFiniteDifferences(this.datahandle, evalSol, this.fdStep); + + sensitivity = df.dy(tspan, y0, this.parameters, sensitivity); + if nDirY < size(sensitivity, 2) + sensitivity(:, 1+nDirY:end) = sensitivity(:, 1+nDirY:end) + df.dp(tspan, y0, this.parameters, this.dirP); + end + end + function [sens, fPlus] = applySensitivitySwitchUpdate(this, sens, idxModel, fMinus) tMinus = this.switchesLeft(idxModel); tPlus = this.switches(idxModel); From 434a151f00443ffad97e276315ae2211f7a82591 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Fri, 26 Jun 2026 16:56:17 +0200 Subject: [PATCH 19/24] Simplify finite difference code --- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 8 +- .../IFDIFFDerivativeFiniteDifferences.m | 96 ++++++++++--------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 0270c27..5e1f3f8 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -91,7 +91,7 @@ function sol = solveVde(this, idxModel, tspan, initialValues, nDirY) rhs = getRhsFromModelNum(this.datahandle, idxModel); - df = IFDIFFDerivativeFiniteDifferences(this.datahandle, rhs, this.fdStep); + df = IFDIFFDerivativeFiniteDifferences(this.datahandle, rhs, this.dimy, this.fdStep); rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, df, this.dirP); initialValues = initialValues(:); @@ -111,7 +111,7 @@ @(t, y) rhs(datahandle, t, y, p), ... tspan, y0, this.integratorOptions); evalSol = @(datahandle, t, y0, p) deval(solve(datahandle, t, y0, p), t); - df = IFDIFFDerivativeFiniteDifferences(this.datahandle, evalSol, this.fdStep); + df = IFDIFFDerivativeFiniteDifferences(this.datahandle, evalSol, this.dimy, this.fdStep); sensitivity = df.dy(tspan, y0, this.parameters, sensitivity); if nDirY < size(sensitivity, 2) @@ -138,9 +138,9 @@ sigma = this.switchingFunctions{idxModel}; jump = this.jumpFunctions{idxModel}; - dsigma = IFDIFFDerivativeFiniteDifferences([], sigma, this.fdStep); + dsigma = IFDIFFDerivativeFiniteDifferences([], sigma, 1, this.fdStep); if ~isempty(jump) - djump = IFDIFFDerivativeFiniteDifferences([], jump, this.fdStep); + djump = IFDIFFDerivativeFiniteDifferences([], jump, this.dimy, this.fdStep); else djump = []; end diff --git a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m index 6366594..b1f09f7 100644 --- a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m +++ b/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m @@ -17,16 +17,19 @@ properties (Access=public) datahandle f % out = f(datahandle, t, y, p) + dimOut step % from generateFDstep end + methods (Access=public) - function this = IFDIFFDerivativeFiniteDifferences(datahandle, f, step) + function this = IFDIFFDerivativeFiniteDifferences(datahandle, f, dimOut, step) if nargin == 0 return end this.datahandle = datahandle; this.f = f; + this.dimOut = dimOut; this.step = step; end @@ -35,67 +38,72 @@ % because these functions will be called many times by the integrator when solving the VDE and we want to avoid % performance loss due to overhead from anonymous functions. function df = dt(this, t, y, p, v) - f0 = this.f(this.datahandle, t, y, p); - - dimf = length(f0); - nd = size(v, 2); - df = zeros(dimf, nd); - - h = this.ht(t); - [v, h, normv, idxNonzero] = this.scaleDirections(t, v, h); + x = t; + h = this.ht(x); + [df, v, h, idxNonzero, f0] = this.init(x, t, y, p, v, h); if isempty(idxNonzero) return end - - for i=1:length(idxNonzero) + % Evaluate function at forward points. + for i=idxNonzero fh = this.f(this.datahandle, v(:, i), y, p); - df(:, idxNonzero(i)) = (fh - f0) ./ h(i); + df(:, i, :) = fh; end - df(:, idxNonzero) = df(:, idxNonzero) .* normv(idxNonzero); + % Compute finite differences. + df(:, idxNonzero, :) = (df(:, idxNonzero, :) - f0) ./ h; end function df = dy(this, t, y, p, v) - f0 = this.f(this.datahandle, t, y, p); - - [dimf, nt] = size(f0); - nd = size(v, 2); - df = zeros(dimf, nd, nt); - - h = this.hy(y); - [v, h, normv, idxNonzero] = this.scaleDirections(y, v, h); + x = y; + h = this.hy(x); + [df, v, h, idxNonzero, f0] = this.init(x, t, y, p, v, h); if isempty(idxNonzero) return end - - for i=1:length(idxNonzero) + % Evaluate function at forward points. + for i=idxNonzero fh = this.f(this.datahandle, t, v(:, i), p); - df(:, idxNonzero(i), :) = (fh - f0) ./ h(i); + df(:, i, :) = fh; end - df(:, idxNonzero, :) = df(:, idxNonzero, :) .* normv(idxNonzero); + % Compute finite differences. + df(:, idxNonzero, :) = (df(:, idxNonzero, :) - f0) ./ h; end function df = dp(this, t, y, p, v) - f0 = this.f(this.datahandle, t, y, p); - - [dimf, nt] = size(f0); - nd = size(v, 2); - df = zeros(dimf, nd, nt); - - h = this.hp(p); - [v, h, normv, idxNonzero] = this.scaleDirections(p, v, h); + x = p; + h = this.hp(x); + [df, v, h, idxNonzero, f0] = this.init(x, t, y, p, v, h); if isempty(idxNonzero) return end - - for i=1:length(idxNonzero) + % Evaluate function at forward points. + for i=idxNonzero fh = this.f(this.datahandle, t, y, v(:, i)); - df(:, idxNonzero(i), :) = (fh - f0) ./ h(i); + df(:, i, :) = fh; end - df(:, idxNonzero, :) = df(:, idxNonzero, :) .* normv(idxNonzero); + % Compute finite differences. + df(:, idxNonzero, :) = (df(:, idxNonzero, :) - f0) ./ h; end end %% Helper functions - methods (Static, Access=private) - function [v, h, normv, idxNonzero] = scaleDirections(x, v, h) + methods (Access=private) + function [df, v, h, idxNonzero, f0] = init(this, x, t, y, p, v, h) + % Init output: Derivatives are stored column-wise for each direction giving a matrix for each time point. + nv = size(v, 2); + nt = length(t); + df = zeros(this.dimOut, nv, nt); + % Compute forward evaluation points. + [v, h, idxNonzero] = this.scaleDirections(x, v, h); + % Compute function value at target point if needed. + if ~isempty(idxNonzero) + f0 = this.f(this.datahandle, t, y, p); + else + f0 = []; + end + end + end + + methods (Static, Access=public) + function [v, h, idxNonzero] = scaleDirections(x, v, h) % Filter zero directions. normv = vecnorm(v, 2, 1); idxNonzero = find(normv); @@ -103,16 +111,18 @@ return end % Scale each non-zero direction to unit length. - v = v(:, idxNonzero) ./ normv(idxNonzero); + v(:, idxNonzero) = v(:, idxNonzero) ./ normv(idxNonzero); % Assume that h is a column vector which contains a step size for each component. % To determine the step size for an arbitrary direction v compute the scalar product of h and v. - h = h' * v; - v = x + v.*h; + h = h' * v(:, idxNonzero); + v(:, idxNonzero) = x + v(:, idxNonzero) .* h; + % Restore scaling for finite differences. + h = h ./ normv(idxNonzero); end end %% Step size - methods (Access=private) + methods (Access=public) function h = ht(this, t) if this.step.t_rel h = max(this.step.t_min, abs(t) .* this.step.t); From 4f63b9374d8e2905330e8dced991fa837c689962 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Fri, 26 Jun 2026 17:54:20 +0200 Subject: [PATCH 20/24] Provide dense output for sensitivity END solver --- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 60 ++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index 5e1f3f8..c6fdb3d 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -31,6 +31,35 @@ 'END_full', 3) end + methods (Static) + function f = getFiniteDifferenceSolFun(sol, solDisturbY, solDisturbP, hy, hp, dim) + f = @computeSens; + nDir = length(solDisturbY); + + function sens = computeSens(t) + nt = length(t); + sens = zeros(dim, nDir, nt); + + solT = []; + for i=1:nDir + solY = solDisturbY{i}; + solP = solDisturbP{i}; + % Make sure we evaluate the solution only once if needed. + if isempty(solT) && (~isempty(solY) | ~isempty(solT)) + solT = deval(sol, t); + end + + if ~isempty(solY) + sens(:, i, :) = (deval(solY) - solT) ./ hy; + end + if ~isempty(solP) + sens(:, i, :) = sens(:, i, :) + (deval(solP) - solT) ./ hp; + end + end + end + end + end + methods function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP, fdStep, method) if nargin < 8 @@ -98,7 +127,7 @@ sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); end - function sensitivity = solveEnd(this, idxModel, tspan, sensitivity, nDirY) + function sensFun = solveEnd(this, idxModel, tspan, sensitivity, nDirY) rhs = getRhsFromModelNum(this.datahandle, idxModel); if idxModel == 1 @@ -107,16 +136,29 @@ y0 = this.switchesY(:, idxModel - 1); end - solve = @(datahandle, t, y0, p) this.integrator( ... - @(t, y) rhs(datahandle, t, y, p), ... - tspan, y0, this.integratorOptions); - evalSol = @(datahandle, t, y0, p) deval(solve(datahandle, t, y0, p), t); - df = IFDIFFDerivativeFiniteDifferences(this.datahandle, evalSol, this.dimy, this.fdStep); - sensitivity = df.dy(tspan, y0, this.parameters, sensitivity); - if nDirY < size(sensitivity, 2) - sensitivity(:, 1+nDirY:end) = sensitivity(:, 1+nDirY:end) + df.dp(tspan, y0, this.parameters, this.dirP); + nDir = size(sensitivity, 2); + solDisturbY = cell(1, nDir); + solDisturbP = cell(1, nDir); + % Solve with disturbed initial values. + fd = IFDIFFDerivativeFiniteDifferences([], [], [], this.fdStep); + hy = fd.hy(y0); + [yh, hy, idxNonzeroY] = fd.scaleDirections(y0, sensitivity, hy); + for i=idxNonzeroY + solDisturbY{i} = this.integrator( ... + @(t, y) rhs(this.datahandle, t, y, this.parameters), tspan, yh(:, i), this.integratorOptions); + end + % Solve with disturbed parameters. + if nDirY < nDir + hp = fd.hp(this.parameters); + [ph, hp, idxNonzeroP] = fd.scaleDirections(this.parameters, this.dirP, hp); end + for i=1:idxNonzeroP + solDisturbP{i} = this.integrator( ... + @(t, y) rhs(this.datahandle, t, y, ph(:, i)), tspan, y0, this.integratorOptions); + end + + sensFun = this.getFiniteDifferenceSolFun(this.solution, solDisturbY, solDisturbP, hy, hp, this.dimy); end function [sens, fPlus] = applySensitivitySwitchUpdate(this, sens, idxModel, fMinus) From 10da32fdd5517afad9084298e64a75c497e95130 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 28 Jun 2026 13:17:45 +0200 Subject: [PATCH 21/24] Add END piecewise solver for directional sensitivities --- tests/TestStateJumps.m | 2 +- toolbox/generateSensitivityFunction.m | 12 +-- .../@IFDIFFSensitivity/IFDIFFSensitivity.m | 94 ++++++++++++++----- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/tests/TestStateJumps.m b/tests/TestStateJumps.m index af166f2..0aea941 100644 --- a/tests/TestStateJumps.m +++ b/tests/TestStateJumps.m @@ -293,7 +293,7 @@ function testSensitivitiesSimpleEND_piecewise(testCase) rtol2 = 1e-5; sensFun = generateSensitivityFunction(datahandle, sol, 'method', 'END_piecewise', ... - 'CalcGy', true, 'CalcGp', true, 'Gmatrices_intermediate', true); + 'CalcGy', true, 'CalcGp', true, 'Gmatrices_intermediate', false); t1 = sol.switches(1); t1Minus = leftLimit(t1); diff --git a/toolbox/generateSensitivityFunction.m b/toolbox/generateSensitivityFunction.m index 12362cf..4e2d5d7 100644 --- a/toolbox/generateSensitivityFunction.m +++ b/toolbox/generateSensitivityFunction.m @@ -38,7 +38,7 @@ FDstep = olGetOption(varargin, 'FDstep', generateFDstep(dim_y, dim_p)); integrator = olGetOption(varargin, 'integrator', data.integratorSettings.numericIntegrator); integrator_options = olGetOption(varargin, 'integrator_options', data.integratorSettings.options); -method = olGetOption(varargin, 'method', 'VDE'); +methodStr = olGetOption(varargin, 'method', 'VDE'); Gmatrices_intermediate_flag = olGetOption(varargin, 'Gmatrices_intermediate', false); Gy_flag = olGetOption(varargin, 'calcGy', true); directions_y = olGetOption(varargin, 'directions_y', []); @@ -51,9 +51,9 @@ methodCoded.VDE = 2; methodCoded.END_full = 3; -if strcmpi(method, 'END_piecewise'),method = methodCoded.END_piecewise; end -if strcmpi(method, 'VDE'), method = methodCoded.VDE; end -if strcmpi(method, 'END_full'), method = methodCoded.END_full; end +if strcmpi(methodStr, 'END_piecewise'),method = methodCoded.END_piecewise; end +if strcmpi(methodStr, 'VDE'), method = methodCoded.VDE; end +if strcmpi(methodStr, 'END_full'), method = methodCoded.END_full; end % switches includes tspan(1) and tspan(end) switches = data.computeSensitivity.switches_extended; @@ -103,7 +103,7 @@ % TODO: Combine legacy and new computation methods. - if ~legacy && method == methodCoded.VDE + if ~legacy && method ~= methodCoded.END_full if Gmatrices_intermediate_flag msg = [ 'Intermediate matrices can not be computed for directional sensitivities.\n', ... @@ -111,7 +111,7 @@ error('IFDIFF:Sensitivity:DirectionalIntermediateMatrices', msg); end - sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, directions_y, directions_p, FDstep); + sensObj = IFDIFFSensitivity(datahandle, sol, Gy_flag, Gp_flag, directions_y, directions_p, FDstep, methodStr); sens = sensObj.eval(t_all); nPoints = size(sens, 3); % TODO: For now keep compatibility with inefficient legacy format output. diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m index c6fdb3d..cf8220d 100644 --- a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m +++ b/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m @@ -24,6 +24,10 @@ method end + properties (Access=private) + solver + end + properties (Constant) METHOD = struct( ... 'VDE', 1, ... @@ -32,7 +36,7 @@ end methods (Static) - function f = getFiniteDifferenceSolFun(sol, solDisturbY, solDisturbP, hy, hp, dim) + function f = getFiniteDifferenceSolFun(sol, dim, solDisturbY, solDisturbP, hy, hp) f = @computeSens; nDir = length(solDisturbY); @@ -50,20 +54,21 @@ end if ~isempty(solY) - sens(:, i, :) = (deval(solY) - solT) ./ hy; + sens(:, i, :) = (deval(solY, t) - solT) ./ hy(i); end if ~isempty(solP) - sens(:, i, :) = sens(:, i, :) + (deval(solP) - solT) ./ hp; + sens(:, i, :) = sens(:, i, :) + reshape((deval(solP, t) - solT) ./ hp(i), dim, 1, nt); end end + sens = reshape(sens, [], nt); end end end methods function this = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP, fdStep, method) - if nargin < 8 - method = 'VDE'; + if nargin == 0 + return; end this.datahandle = datahandle; @@ -115,19 +120,32 @@ this.fdStep = fdStep; - this.method = this.METHOD.(method); + methodNum = this.METHOD.(method); + switch methodNum + case this.METHOD.VDE + this.solver = @this.solveVde; + case this.METHOD.END_piecewise + this.solver = @this.solveEnd; + otherwise + id = 'IFDIFF:Sensitivity:UnrecognizedSolver'; + msg = 'The solver with number %d derived from string ''%s'' does not exist.'; + error(id, msg, methodNum, method); + end end - function sol = solveVde(this, idxModel, tspan, initialValues, nDirY) + function [sensEnd, sensFun] = solveVde(this, idxModel, tspan, sensStart, nDirY) rhs = getRhsFromModelNum(this.datahandle, idxModel); df = IFDIFFDerivativeFiniteDifferences(this.datahandle, rhs, this.dimy, this.fdStep); rhsVde = @(t, G) vdeRhs(t, G, this.parameters, this.solution, nDirY, df, this.dirP); - initialValues = initialValues(:); - sol = this.integrator(rhsVde, tspan, initialValues, this.integratorOptions); + sensStart = sensStart(:); + sol = this.integrator(rhsVde, tspan, sensStart, this.integratorOptions); + + sensEnd = sol.y(:, end); + sensFun = @(t) deval(sol, t); end - function sensFun = solveEnd(this, idxModel, tspan, sensitivity, nDirY) + function [sensEnd, sensFun] = solveEnd(this, idxModel, tspan, sensStart, nDirY) rhs = getRhsFromModelNum(this.datahandle, idxModel); if idxModel == 1 @@ -136,29 +154,49 @@ y0 = this.switchesY(:, idxModel - 1); end - - nDir = size(sensitivity, 2); + nDir = size(sensStart, 2); solDisturbY = cell(1, nDir); solDisturbP = cell(1, nDir); % Solve with disturbed initial values. fd = IFDIFFDerivativeFiniteDifferences([], [], [], this.fdStep); hy = fd.hy(y0); - [yh, hy, idxNonzeroY] = fd.scaleDirections(y0, sensitivity, hy); + [yh, hy, idxNonzeroY] = fd.scaleDirections(y0, sensStart, hy); + % Pad to full length to avoid indexing issues. + hyFull = zeros(1, nDir); + hyFull(idxNonzeroY) = hy; for i=idxNonzeroY solDisturbY{i} = this.integrator( ... @(t, y) rhs(this.datahandle, t, y, this.parameters), tspan, yh(:, i), this.integratorOptions); end % Solve with disturbed parameters. + hpFull = []; if nDirY < nDir hp = fd.hp(this.parameters); [ph, hp, idxNonzeroP] = fd.scaleDirections(this.parameters, this.dirP, hp); - end - for i=1:idxNonzeroP - solDisturbP{i} = this.integrator( ... - @(t, y) rhs(this.datahandle, t, y, ph(:, i)), tspan, y0, this.integratorOptions); + % Pad to full length to avoid indexing issues. + hpFull = zeros(1, nDir); + hpFull(nDirY + idxNonzeroP) = hp; + for i=idxNonzeroP + solDisturbP{nDirY + i} = this.integrator( ... + @(t, y) rhs(this.datahandle, t, y, ph(:, i)), tspan, y0, this.integratorOptions); + end end - sensFun = this.getFiniteDifferenceSolFun(this.solution, solDisturbY, solDisturbP, hy, hp, this.dimy); + sensEnd = zeros(this.dimy, nDir); + % Re-solve the undisturbed RHS here to be more consistent with the disturbed solution. + sol = this.integrator(@(t, y) rhs(this.datahandle, t, y, this.parameters), tspan, y0, this.integratorOptions); + yEnd = deval(sol, tspan(end)); + for i=1:nDir + solY = solDisturbY{i}; + solP = solDisturbP{i}; + if ~isempty(solY) + sensEnd(:, i) = (solY.y(:, end) - yEnd) ./ hyFull(i); + end + if ~isempty(solP) + sensEnd(:, i) = sensEnd(:, i) + (solP.y(:, end) - yEnd) ./ hpFull(i); + end + end + sensFun = this.getFiniteDifferenceSolFun(sol, this.dimy, solDisturbY, solDisturbP, hyFull, hpFull); end function [sens, fPlus] = applySensitivitySwitchUpdate(this, sens, idxModel, fMinus) @@ -194,7 +232,7 @@ dsigma, djump); end - function [sens, sensSol] = eval(this, timepoints) + function [sens, sensFun] = eval(this, timepoints) % Ensure timepoints are strictly increasing. [t, ~, idxTimepointsUndoSort] = unique(timepoints); @@ -215,12 +253,18 @@ nDirY = size(this.dirY, 2); % Integrate each submodel until switch and apply update at the end. + nModels = idxModelEnd - idxModelStart + 1; % Guaranteed to be greater than zero. + sensFun = cell(1, nModels); for idxModel=idxModelStart:idxModelEnd-1 tModelEnd = this.switchesLeft(idxModel); - sensSol(idxModel) = this.solveVde(idxModel, [tModelStart, tModelEnd], sensInitialValue, nDirY); %#ok + [sensEnd, sensFun{idxModel - idxModelStart + 1}] = this.solver( ... + idxModel, [tModelStart, tModelEnd], sensInitialValue, nDirY); + + % Prepare next model. tModelStart = this.switches(idxModel); - % Update initial value for next VDE at switch. - sensInitialValue = reshape(sensSol(idxModel).y(:, end), this.dimy, []); + % Update initial value for next VDE at switch using update formula. + sensInitialValue = reshape(sensEnd, this.dimy, []); + % Setup fMinus beforehand for the first update. Next updates can just use fPlus from the preceding update. if idxModel == idxModelStart fMinus = getRhsFromModelNum(this.datahandle, idxModelStart); end @@ -228,11 +272,11 @@ end % No more switches left, so solve until the end. tModelEnd = t(end); - sensSol(idxModelEnd) = this.solveVde(idxModelEnd, [tModelStart, tModelEnd], sensInitialValue, nDirY); + [~, sensFun{idxModelEnd - idxModelStart + 1}] = this.solver( ... + idxModelEnd, [tModelStart, tModelEnd], sensInitialValue, nDirY); % Return sensitivity at requested timepoints - piecewiseFunc = arrayfun(@(sol) @(t) deval(sol, t), sensSol, 'UniformOutput', false); - sens = evalPiecewiseFunc(t, piecewiseFunc, numel(sensInitialValue), this.switches); + sens = evalPiecewiseFunc(t, sensFun, numel(sensInitialValue), this.switches); sens = reshape(sens, this.dimy, size(sensInitialValue, 2), []); sens = sens(:, :, idxTimepointsUndoSort); end From 83810dba22ac26cc3a205317f0a892af45a4f1d6 Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 28 Jun 2026 15:23:30 +0200 Subject: [PATCH 22/24] Remove old temporary sensitivity test code --- toolbox/internal/_sensNew/testSensNew.m | 103 ------------------------ 1 file changed, 103 deletions(-) delete mode 100644 toolbox/internal/_sensNew/testSensNew.m diff --git a/toolbox/internal/_sensNew/testSensNew.m b/toolbox/internal/_sensNew/testSensNew.m deleted file mode 100644 index b458101..0000000 --- a/toolbox/internal/_sensNew/testSensNew.m +++ /dev/null @@ -1,103 +0,0 @@ -%% Setup -% Canonical Example -rhs = @canonicalExampleRHS; -tspan = [0, 100]; -initialvalues = [1; 0]; -parameters = 5.437; -dimy = length(initialvalues); -dimp = length(parameters); - -integrator = @ode45; -opts = odeset('AbsTol', 1e-12, 'RelTol', 1e-10); - -%% Preprocess -datahandle = prepareDatahandleForIntegration(rhs, 'integrator', integrator, 'options', opts); - -%% Solve -sol = solveODE(datahandle, tspan, initialvalues, parameters); -sw = sol.switches; - -%% Sensitivity -dirY = []; -calcGy = true; -%dirY = [1, 0; 0, 1; 1, 1]'; -calcGp = false; -dirP = []; -if calcGy && isempty(dirY) - nDirY = length(initialvalues); -else - nDirY = size(dirY, 2); -end -if calcGp && isempty(dirP) - nDirP = length(parameters); -else - nDirP = size(dirP, 2); -end -%t = linspace(tspan(1), tspan(2), 1000); -%t = (sol.switches(1)-0.5):0.001:(sol.switches(2)+0.5); -t = jumpLinspace(tspan(1), tspan(end), sol.switches, 1e5); -nt = length(t); -h = sqrt(eps); -fdStep = generateFDstep(dimy, dimp, 'ht', h, 'hy', h, 'hp', h); - -%sensObj = IFDIFFSensitivity(datahandle, sol, calcGy, calcGp, dirY, dirP); -%[sensT, sensSol] = sensObj.eval(t); -sensFunOld = generateSensitivityFunction(datahandle, sol, fdStep, 'calcGy', calcGy, 'calcGp', calcGp, ... -'directions_y', dirY, 'directions_p', dirP, 'legacy', true, 'Gmatrices_intermediate', true); -sensFunNew = generateSensitivityFunction(datahandle, sol, fdStep, 'calcGy', calcGy, 'calcGp', calcGp, ... - 'directions_y', dirY, 'directions_p', dirP); -sensOld = sensFunOld(t); -sensNew = sensFunNew(t); - -%% Compare -sdOld = zeros(dimy, nDirY); -sdNew = zeros(dimy, nDirY); - -for i=1:nt - sdOld(:, :, i) = sensOld(i).Gy; - sdNew(:, :, i) = sensNew(i).Gy; -end -plotTiled(t, abs(sdOld - sdNew), nDirY, nDirP); - -%% Plot directly -plotTiled(t, sensT, nDirY, nDirP) - -%% Plot via sol -y = []; -tidx = 1; -for i=1:length(sw)+1 - if i < length(sw)+1 - tidxnew = tidx + find(t(tidx:end) >= sw(i), 1) - 1; - ti = t(tidx:tidxnew-1); - else - ti = t(tidx:end); - end - yi = reshape(deval(sensSol(i), ti), length(initialvalues), nDirY + nDirP, []); - y = cat(3, y, yi); - tidx = tidxnew; -end -plotTiled(t, y, nDirY, nDirP) - - -%% Helper -function plotTiled(t, y, nDirY, nDirP) -nPrev = 0; -for nDir=[nDirY, nDirP] - if nDir == 0 - continue - end - figure; - axs = []; - tiledlayout(size(y, 1), nDir); - for i=1:size(y, 1) - for j=1:nDir - axs(i,j) = nexttile; %#ok - plot(t, squeeze(y(i, nPrev + j, :))); - title(sprintf('G_{%d%d}', i, j)) - end - end - ylim tight - linkaxes(axs) - nPrev = nDir; -end -end From a5cfc49bde09c81a2a0f46659aa86979a35877ba Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Sun, 28 Jun 2026 15:27:09 +0200 Subject: [PATCH 23/24] Move old sensitivity code to separate directory --- toolbox/internal/{_sensNew => sensitivities}/IFDIFFDerivative.m | 0 .../IFDIFFDerivativeFiniteDifferences.m | 0 .../@IFDIFFSensitivity => sensitivities}/IFDIFFSensitivity.m | 0 .../{_sensNew => sensitivities}/computeSensitivitySwitchUpdate.m | 0 toolbox/internal/{_sensNew => sensitivities}/evalPiecewiseFunc.m | 0 toolbox/internal/sensitivities/{ => legacy}/VDE_RHS_p.m | 0 toolbox/internal/sensitivities/{ => legacy}/VDE_RHS_y.m | 0 .../sensitivities/{ => legacy}/assembleSensitivityOutput.m | 0 .../sensitivities/{ => legacy}/compute_sensitivity_ENDfull.m | 0 .../sensitivities/{ => legacy}/compute_sensitivity_ENDfull_p.m | 0 .../sensitivities/{ => legacy}/compute_sensitivity_ENDfull_y.m | 0 toolbox/internal/sensitivities/{ => legacy}/del_f_del_p.m | 0 toolbox/internal/sensitivities/{ => legacy}/del_f_del_t.m | 0 toolbox/internal/sensitivities/{ => legacy}/del_f_del_y.m | 0 toolbox/internal/sensitivities/{ => legacy}/fdStep_getH_p.m | 0 toolbox/internal/sensitivities/{ => legacy}/fdStep_getH_t.m | 0 toolbox/internal/sensitivities/{ => legacy}/fdStep_getH_y.m | 0 toolbox/internal/sensitivities/{ => legacy}/generateData.m | 0 toolbox/internal/sensitivities/{ => legacy}/generateSensData.m | 0 toolbox/internal/sensitivities/{ => legacy}/generateStructArray.m | 0 .../internal/sensitivities/{ => legacy}/getGp_intermediate_END.m | 0 .../internal/sensitivities/{ => legacy}/getGp_intermediate_VDE.m | 0 toolbox/internal/sensitivities/{ => legacy}/getGy_Gp_update.m | 0 .../internal/sensitivities/{ => legacy}/getGy_intermediate_END.m | 0 .../internal/sensitivities/{ => legacy}/getGy_intermediate_VDE.m | 0 toolbox/internal/sensitivities/{ => legacy}/solveDisturbed_Gp.m | 0 toolbox/internal/sensitivities/{ => legacy}/solveDisturbed_Gy.m | 0 toolbox/internal/sensitivities/{ => legacy}/solveVDE_Gp.m | 0 toolbox/internal/sensitivities/{ => legacy}/solveVDE_Gy.m | 0 toolbox/internal/{_sensNew => sensitivities}/vdeRhs.m | 0 30 files changed, 0 insertions(+), 0 deletions(-) rename toolbox/internal/{_sensNew => sensitivities}/IFDIFFDerivative.m (100%) rename toolbox/internal/{_sensNew => sensitivities}/IFDIFFDerivativeFiniteDifferences.m (100%) rename toolbox/internal/{_sensNew/@IFDIFFSensitivity => sensitivities}/IFDIFFSensitivity.m (100%) rename toolbox/internal/{_sensNew => sensitivities}/computeSensitivitySwitchUpdate.m (100%) rename toolbox/internal/{_sensNew => sensitivities}/evalPiecewiseFunc.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/VDE_RHS_p.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/VDE_RHS_y.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/assembleSensitivityOutput.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/compute_sensitivity_ENDfull.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/compute_sensitivity_ENDfull_p.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/compute_sensitivity_ENDfull_y.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/del_f_del_p.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/del_f_del_t.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/del_f_del_y.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/fdStep_getH_p.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/fdStep_getH_t.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/fdStep_getH_y.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/generateData.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/generateSensData.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/generateStructArray.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/getGp_intermediate_END.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/getGp_intermediate_VDE.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/getGy_Gp_update.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/getGy_intermediate_END.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/getGy_intermediate_VDE.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/solveDisturbed_Gp.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/solveDisturbed_Gy.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/solveVDE_Gp.m (100%) rename toolbox/internal/sensitivities/{ => legacy}/solveVDE_Gy.m (100%) rename toolbox/internal/{_sensNew => sensitivities}/vdeRhs.m (100%) diff --git a/toolbox/internal/_sensNew/IFDIFFDerivative.m b/toolbox/internal/sensitivities/IFDIFFDerivative.m similarity index 100% rename from toolbox/internal/_sensNew/IFDIFFDerivative.m rename to toolbox/internal/sensitivities/IFDIFFDerivative.m diff --git a/toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m b/toolbox/internal/sensitivities/IFDIFFDerivativeFiniteDifferences.m similarity index 100% rename from toolbox/internal/_sensNew/IFDIFFDerivativeFiniteDifferences.m rename to toolbox/internal/sensitivities/IFDIFFDerivativeFiniteDifferences.m diff --git a/toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m b/toolbox/internal/sensitivities/IFDIFFSensitivity.m similarity index 100% rename from toolbox/internal/_sensNew/@IFDIFFSensitivity/IFDIFFSensitivity.m rename to toolbox/internal/sensitivities/IFDIFFSensitivity.m diff --git a/toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m b/toolbox/internal/sensitivities/computeSensitivitySwitchUpdate.m similarity index 100% rename from toolbox/internal/_sensNew/computeSensitivitySwitchUpdate.m rename to toolbox/internal/sensitivities/computeSensitivitySwitchUpdate.m diff --git a/toolbox/internal/_sensNew/evalPiecewiseFunc.m b/toolbox/internal/sensitivities/evalPiecewiseFunc.m similarity index 100% rename from toolbox/internal/_sensNew/evalPiecewiseFunc.m rename to toolbox/internal/sensitivities/evalPiecewiseFunc.m diff --git a/toolbox/internal/sensitivities/VDE_RHS_p.m b/toolbox/internal/sensitivities/legacy/VDE_RHS_p.m similarity index 100% rename from toolbox/internal/sensitivities/VDE_RHS_p.m rename to toolbox/internal/sensitivities/legacy/VDE_RHS_p.m diff --git a/toolbox/internal/sensitivities/VDE_RHS_y.m b/toolbox/internal/sensitivities/legacy/VDE_RHS_y.m similarity index 100% rename from toolbox/internal/sensitivities/VDE_RHS_y.m rename to toolbox/internal/sensitivities/legacy/VDE_RHS_y.m diff --git a/toolbox/internal/sensitivities/assembleSensitivityOutput.m b/toolbox/internal/sensitivities/legacy/assembleSensitivityOutput.m similarity index 100% rename from toolbox/internal/sensitivities/assembleSensitivityOutput.m rename to toolbox/internal/sensitivities/legacy/assembleSensitivityOutput.m diff --git a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull.m b/toolbox/internal/sensitivities/legacy/compute_sensitivity_ENDfull.m similarity index 100% rename from toolbox/internal/sensitivities/compute_sensitivity_ENDfull.m rename to toolbox/internal/sensitivities/legacy/compute_sensitivity_ENDfull.m diff --git a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_p.m b/toolbox/internal/sensitivities/legacy/compute_sensitivity_ENDfull_p.m similarity index 100% rename from toolbox/internal/sensitivities/compute_sensitivity_ENDfull_p.m rename to toolbox/internal/sensitivities/legacy/compute_sensitivity_ENDfull_p.m diff --git a/toolbox/internal/sensitivities/compute_sensitivity_ENDfull_y.m b/toolbox/internal/sensitivities/legacy/compute_sensitivity_ENDfull_y.m similarity index 100% rename from toolbox/internal/sensitivities/compute_sensitivity_ENDfull_y.m rename to toolbox/internal/sensitivities/legacy/compute_sensitivity_ENDfull_y.m diff --git a/toolbox/internal/sensitivities/del_f_del_p.m b/toolbox/internal/sensitivities/legacy/del_f_del_p.m similarity index 100% rename from toolbox/internal/sensitivities/del_f_del_p.m rename to toolbox/internal/sensitivities/legacy/del_f_del_p.m diff --git a/toolbox/internal/sensitivities/del_f_del_t.m b/toolbox/internal/sensitivities/legacy/del_f_del_t.m similarity index 100% rename from toolbox/internal/sensitivities/del_f_del_t.m rename to toolbox/internal/sensitivities/legacy/del_f_del_t.m diff --git a/toolbox/internal/sensitivities/del_f_del_y.m b/toolbox/internal/sensitivities/legacy/del_f_del_y.m similarity index 100% rename from toolbox/internal/sensitivities/del_f_del_y.m rename to toolbox/internal/sensitivities/legacy/del_f_del_y.m diff --git a/toolbox/internal/sensitivities/fdStep_getH_p.m b/toolbox/internal/sensitivities/legacy/fdStep_getH_p.m similarity index 100% rename from toolbox/internal/sensitivities/fdStep_getH_p.m rename to toolbox/internal/sensitivities/legacy/fdStep_getH_p.m diff --git a/toolbox/internal/sensitivities/fdStep_getH_t.m b/toolbox/internal/sensitivities/legacy/fdStep_getH_t.m similarity index 100% rename from toolbox/internal/sensitivities/fdStep_getH_t.m rename to toolbox/internal/sensitivities/legacy/fdStep_getH_t.m diff --git a/toolbox/internal/sensitivities/fdStep_getH_y.m b/toolbox/internal/sensitivities/legacy/fdStep_getH_y.m similarity index 100% rename from toolbox/internal/sensitivities/fdStep_getH_y.m rename to toolbox/internal/sensitivities/legacy/fdStep_getH_y.m diff --git a/toolbox/internal/sensitivities/generateData.m b/toolbox/internal/sensitivities/legacy/generateData.m similarity index 100% rename from toolbox/internal/sensitivities/generateData.m rename to toolbox/internal/sensitivities/legacy/generateData.m diff --git a/toolbox/internal/sensitivities/generateSensData.m b/toolbox/internal/sensitivities/legacy/generateSensData.m similarity index 100% rename from toolbox/internal/sensitivities/generateSensData.m rename to toolbox/internal/sensitivities/legacy/generateSensData.m diff --git a/toolbox/internal/sensitivities/generateStructArray.m b/toolbox/internal/sensitivities/legacy/generateStructArray.m similarity index 100% rename from toolbox/internal/sensitivities/generateStructArray.m rename to toolbox/internal/sensitivities/legacy/generateStructArray.m diff --git a/toolbox/internal/sensitivities/getGp_intermediate_END.m b/toolbox/internal/sensitivities/legacy/getGp_intermediate_END.m similarity index 100% rename from toolbox/internal/sensitivities/getGp_intermediate_END.m rename to toolbox/internal/sensitivities/legacy/getGp_intermediate_END.m diff --git a/toolbox/internal/sensitivities/getGp_intermediate_VDE.m b/toolbox/internal/sensitivities/legacy/getGp_intermediate_VDE.m similarity index 100% rename from toolbox/internal/sensitivities/getGp_intermediate_VDE.m rename to toolbox/internal/sensitivities/legacy/getGp_intermediate_VDE.m diff --git a/toolbox/internal/sensitivities/getGy_Gp_update.m b/toolbox/internal/sensitivities/legacy/getGy_Gp_update.m similarity index 100% rename from toolbox/internal/sensitivities/getGy_Gp_update.m rename to toolbox/internal/sensitivities/legacy/getGy_Gp_update.m diff --git a/toolbox/internal/sensitivities/getGy_intermediate_END.m b/toolbox/internal/sensitivities/legacy/getGy_intermediate_END.m similarity index 100% rename from toolbox/internal/sensitivities/getGy_intermediate_END.m rename to toolbox/internal/sensitivities/legacy/getGy_intermediate_END.m diff --git a/toolbox/internal/sensitivities/getGy_intermediate_VDE.m b/toolbox/internal/sensitivities/legacy/getGy_intermediate_VDE.m similarity index 100% rename from toolbox/internal/sensitivities/getGy_intermediate_VDE.m rename to toolbox/internal/sensitivities/legacy/getGy_intermediate_VDE.m diff --git a/toolbox/internal/sensitivities/solveDisturbed_Gp.m b/toolbox/internal/sensitivities/legacy/solveDisturbed_Gp.m similarity index 100% rename from toolbox/internal/sensitivities/solveDisturbed_Gp.m rename to toolbox/internal/sensitivities/legacy/solveDisturbed_Gp.m diff --git a/toolbox/internal/sensitivities/solveDisturbed_Gy.m b/toolbox/internal/sensitivities/legacy/solveDisturbed_Gy.m similarity index 100% rename from toolbox/internal/sensitivities/solveDisturbed_Gy.m rename to toolbox/internal/sensitivities/legacy/solveDisturbed_Gy.m diff --git a/toolbox/internal/sensitivities/solveVDE_Gp.m b/toolbox/internal/sensitivities/legacy/solveVDE_Gp.m similarity index 100% rename from toolbox/internal/sensitivities/solveVDE_Gp.m rename to toolbox/internal/sensitivities/legacy/solveVDE_Gp.m diff --git a/toolbox/internal/sensitivities/solveVDE_Gy.m b/toolbox/internal/sensitivities/legacy/solveVDE_Gy.m similarity index 100% rename from toolbox/internal/sensitivities/solveVDE_Gy.m rename to toolbox/internal/sensitivities/legacy/solveVDE_Gy.m diff --git a/toolbox/internal/_sensNew/vdeRhs.m b/toolbox/internal/sensitivities/vdeRhs.m similarity index 100% rename from toolbox/internal/_sensNew/vdeRhs.m rename to toolbox/internal/sensitivities/vdeRhs.m From 5506fc874eae39440f82911040fa5432119da04f Mon Sep 17 00:00:00 2001 From: Lev Gromov Date: Mon, 10 Aug 2026 12:32:32 +0200 Subject: [PATCH 24/24] Remove old class diagram --- docs/dev/sensitivity.mmd | 49 ---------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 docs/dev/sensitivity.mmd diff --git a/docs/dev/sensitivity.mmd b/docs/dev/sensitivity.mmd deleted file mode 100644 index e8f9a69..0000000 --- a/docs/dev/sensitivity.mmd +++ /dev/null @@ -1,49 +0,0 @@ -classDiagram - Sensitivity o-- Solution : Describes switching behavior and nominal trajectory - Sensitivity ..> Integrator : Calls to solve VDE (or ODE with disturbed inputs) - Sensitivity ..> Derivative : Calls to compute switch updates and VDE RHS - Integrator ..> Solution : Computes - Derivative <|.. FiniteDifference : Implements - class Sensitivity{ - +Solution nominal_trajectory - +Integrator integrator - +List~float~ switching_timepoints - +function rhs - +List~function~ switching_functions - +List~function~ jump_functions - +List~Derivatives~ derivative_rhs_submodels - +List~Derivative~ derivative_switching_functions - +List~Derivative~ derivative_jump_functions - +List~int~ initial_value_indices_for_which_to_compute - +List~int~ parameter_indices_for_which_to_compute - +float initial_time - +Matrix~float~ initial_value_sensitivity_initial_value - +Matrix~float~ parameter_sensitivity_initial_value - - +evaluate(List~float~ timepoints) List~Vector~float~~ sensitivity_at_timepoints - +get_dense_representation(List~float~ timepoints, List~Vector~float~~ sensitivity_at_timepoints) Solution - } - class Solution{ - +List~float~ timepoints - +List~Vector~float~~ solution_at_timepoints - +evaluate_dense(List~float~ timepoints) List~Vector~float~~ solution_at_timepoints - } - class Integrator{ - +function rhs - +float initial_time - +Vector~float~ initial_value - +Struct options - +solve(List~float~ timepoints) Solution - } - class Derivative{ - <> - +function f - +fdt(float t, Vector~float~ y, Vector~float~ p, float direction) Vector~float~ - +fdy(float t, Vector~float~ y, Vector~float~ p, Matrix~float~ direction) Matrix~float~ - +fdp(float t, Vector~float~ y, Vector~float~ p, Matrix~float~ direction) Matrix~float~ - } - - class FiniteDifference{ - +float step_size - +get_step_size(t, y, p) Vector~float~ - }