diff --git a/ENUME/projectB/Code/printComplexGraph.m b/ENUME/projectB/Code/printComplexGraph.m new file mode 100644 index 00000000..017a620a --- /dev/null +++ b/ENUME/projectB/Code/printComplexGraph.m @@ -0,0 +1,28 @@ +% graph the complex roots of a function +function printComplexGraph(printComplexGraph, algorithmName, algorithm, rootBrackets, plottitle) + figure(); + grid on; % Get y values lines + hold on; % Retain current plot when adding new plots + title([plottitle, algorithmName]); + xlabel("Real part"); + ylabel("Imaginary part"); + set(gca, 'XAxisLocation', 'origin'); % Set properties of current axis + + % find all zeros within the bracket using the given algorithm + [~, steps] = algorithm(printComplexGraph, rootBrackets(1), rootBrackets(2), 1e-15); + + % plot first step + text(real(steps(1, 1)), imag(steps(1, 1)), 'start', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top'); + + % plot steps on graph + plot(real(steps(1, :)), imag(steps(1, :)), '-x'); + + % plot last step + text(real(steps(1, end)), imag(steps(1, end)), 'end', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top'); + + + % print root table + disp([plottitle, ' (', algorithmName, ')']); + columns = {'step', 'root', 'abs value at root'}; + disp(table([1:size(steps, 2)]', steps(1, :)', abs(steps(2, :))', 'VariableNames', columns)); +end diff --git a/ENUME/projectB/Code/printGraph.m b/ENUME/projectB/Code/printGraph.m index f3bc99ba..52a6a936 100644 --- a/ENUME/projectB/Code/printGraph.m +++ b/ENUME/projectB/Code/printGraph.m @@ -1,6 +1,6 @@ % graph the real roots of a function function printGraph(taskFunction, algorithmName, algorithm, interval, rootBrackets, plotTitle) - + figure() grid on; % Get y values lines hold on; % Retain current plot when adding new plots title([plotTitle, algorithmName]); diff --git a/ENUME/projectB/Code/printcomplex.m b/ENUME/projectB/Code/printcomplex.m index e3843aeb..c7155e18 100644 --- a/ENUME/projectB/Code/printcomplex.m +++ b/ENUME/projectB/Code/printcomplex.m @@ -1,5 +1,5 @@ % graph the complex roots of a function -function printcomplex(func, algorithms, bracket, plottitle, outputsuffix) +function printComplexGraph(func, algorithms, bracket, plottitle, outputsuffix) % perform task for all available algorithms for alg = 1:size(algorithms, 1) [algname, algfunc] = algorithms{alg, :}; @@ -29,7 +29,7 @@ function printcomplex(func, algorithms, bracket, plottitle, outputsuffix) hold off; set(gcf, 'PaperPosition', [0 0 6 4]); set(gcf, 'PaperSize', [6 4]); - print(['report/', func2str(algfunc), outputsuffix], '-dpdf'); + printComplexGraph(['report/', func2str(algfunc), outputsuffix], '-dpdf'); % print root table disp([plottitle, ' (', algname, ')']); diff --git a/ENUME/projectB/Code/rootbrac.m b/ENUME/projectB/Code/rootbrac.m deleted file mode 100644 index d84513b8..00000000 --- a/ENUME/projectB/Code/rootbrac.m +++ /dev/null @@ -1,26 +0,0 @@ -% finds the root brackets of a function within the given range -function brackets = rootBracketing(givenFunction, intervalLeft, intervalRight) - % define search resolution - resolution = (intervalRight - intervalLeft) / 10; - - % start search at the start of the range - a = intervalLeft; - b = intervalLeft + resolution; - brackets = double.empty(2, 0); - - % keep moving the interval until the range is exceeded - while 1 - % if the function changes sign inside the interval, a bracket has been found - if sign(givenFunction(a)) ~= sign(givenFunction(b)) - % save bracket - brackets(:, size(brackets, 2) + 1) = [a, b]; - end - - % if the bracket can't be expanded, return - if b == intervalRight; return; end - - % check next bracket - a = b; - b = min(a + resolution, intervalRight); - end -end diff --git a/ENUME/projectB/Code/task2MM1.asv b/ENUME/projectB/Code/task2MM1.asv new file mode 100644 index 00000000..c7b6a7fa --- /dev/null +++ b/ENUME/projectB/Code/task2MM1.asv @@ -0,0 +1,110 @@ +interval = [-5, 10]; +rootBrackets = rootBracketing(@polynomial, interval(1), interval(2)); + +printGraph(@polynomial, 'MM1', @mm1, interval, rootBrackets, 'Approximate zeros of function for method of '); + +printComplexGraph(@polynomial, 'MM1', @mm1, [-1 + i, 0], 'Aproximate complex roots of polynomial'); + +function y = polynomial(x) + y = -2 * x^4 + 12 * x^3 + 4* x^2 + 1 * x + 3; +end + +function [approximation, iterations] = mm1(polynomial, a, b, tolerance) + + [approximation, approximationValue, iterations] = initialize(a, b, polynomial); + [approximation, iterations] = mm1Loop(approximation, tolerance, approximationValue, iterations, polynomial); +end + +function [approximation, approximationValue, iterations] = initialize(a, b, polynomial) + approximation = [a, b, (a + b) / 2]; + approximationValue = arrayfun(polynomial, approximation); + iterations = [approximation(3); polynomial(approximation(3))]; +end + +function [approximation, iterations] = mm1Loop(approximation, tolerance, approximationValue, iterations, polynomial) + while abs(polynomial(approximation(3))) > tolerance + [approximation, approximationValue, iterations] = insideLoop(approximation, approximationValue, polynomial, iterations); + end +end + +function [approximation, approximationValue, iterations] = insideLoop(approximation, approximationValue, polynomial, iterations) + eqsys = createEquationSystem(approximation, approximationValue); + [zplus, zminus] = rootsOfQuadraticFormula(eqsys, approximationValue); + [approximation, approximationValue, iterations] = updateApproximations(zplus, zminus, approximation, iterations, polynomial); +end + +function eqsys = createEquationSystem(approximation, approximationValue) + [z0, z1, diff0, diff1] = initializeEquationSystem(approximation, approximationValue); + eqsys = solveEquationSystem(z0, diff0, z1, diff1); +end + +function [zplus, zminus] = rootsOfQuadraticFormula(eqsys, approximationValue) + [a, b, c] = createApproximatedQuadraticFormula(eqsys, approximationValue); + [zplus, zminus] = findRootsOfQuadraticFormula(a, b, c); +end + +function [approximation, approximationValue, iterations] = updateApproximations(zplus, zminus, approximation, iterations, polynomial) + newapprx = chooseNewRoot(zplus, zminus, approximation); + iterations = addZeroToIterationVector(newapprx, iterations, polynomial); + worstapprxindex = getWorstApproximationIndex(approximation, newapprx); + [approximation, approximationValue] = deleteWorstApproximation(worstapprxindex, approximation, polynomial, newapprx); +end + +function [z0, z1, diff0, diff1] = initializeEquationSystem(approximation, approximationValue) + z0 = approximation(1) - approximation(3); + z1 = approximation(2) - approximation(3); + diff0 = approximationValue(1) - approximationValue(3); + diff1 = approximationValue(2) - approximationValue(3); +end + +function eqsys = solveEquationSystem(z0, diff0, z1, diff1) + eqsys = [z0 ^ 2, z0, diff0; z1 ^ 2, z1, diff1]; + reductor = eqsys(2, 1) / eqsys(1, 1); + eqsys(2, :) = eqsys(2, :) - reductor * eqsys(1, :); + eqsys(2, 1) = 0; + eqsys(2, :) = eqsys(2, :) ./ eqsys(2, 2); + eqsys(1, :) = eqsys(1, :) - eqsys(1, 2) * eqsys(2, :); + eqsys(1, :) = eqsys(1, :) ./ eqsys(1, 1); +end + +function [a, b, c] = createApproximatedQuadraticFormula(eqsys, approximationValue) + a = eqsys(1, 3); + b = eqsys(2, 3); + c = approximationValue(3); +end + +function [zplus, zminus] = findRootsOfQuadraticFormula(a, b, c) + zplus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c)); + zminus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c)); +end + +function newapprx = chooseNewRoot(zplus, zminus, approximation) + if abs(zplus) < abs(zminus) + newapprx = approximation(3) + zplus; + else + newapprx = approximation(3) + zminus; + end +end + +function iterations = addZeroToIterationVector(newapprx, iterations, polynomial) + zero = newapprx; + iterations(:, size(iterations, 2) + 1) = [zero, polynomial(zero)]; +end + +function worstapprxindex = getWorstApproximationIndex(approximation, newapprx) + worstapprxindex = -1; + worstapprxdiff = 0; + for i = 1:size(approximation, 2) + diff = abs(approximation(i) - newapprx); + if diff > worstapprxdiff + worstapprxindex = i; + worstapprxdiff = diff; + end + end +end + +function [approximation, approximationValue] = deleteWorstApproximation(worstapprxindex, approximation, polynomial, newapprx) + approximation(worstapprxindex) = []; + approximation(3) = newapprx; + approximationValue = arrayfun(polynomial, approximation); +end \ No newline at end of file diff --git a/ENUME/projectB/Code/task2MM1.m b/ENUME/projectB/Code/task2MM1.m new file mode 100644 index 00000000..46a7f703 --- /dev/null +++ b/ENUME/projectB/Code/task2MM1.m @@ -0,0 +1,110 @@ +interval = [-5, 10]; +rootBrackets = rootBracketing(@polynomial, interval(1), interval(2)); + +printGraph(@polynomial, 'MM1', @mm1, interval, rootBrackets, 'Approximate zeros of function for method of '); + +printComplexGraph(@polynomial, 'MM1', @mm1, [-1 + i, 0], 'Aproximate complex roots of polynomial'); + +function y = polynomial(x) + y = -2 * x^4 + 12 * x^3 + 4* x^2 + 1 * x + 3; +end + +function [approximation, iterations] = mm1(polynomial, a, b, tolerance) + + [approximation, approximationValue, iterations] = initialize(a, b, polynomial); + [approximation, iterations] = mm1Loop(approximation, tolerance, approximationValue, iterations, polynomial); +end + +function [approximation, approximationValue, iterations] = initialize(a, b, polynomial) + approximation = [a, b, (a + b) / 2]; + approximationValue = arrayfun(polynomial, approximation); + iterations = [approximation(3); polynomial(approximation(3))]; +end + +function [approximation, iterations] = mm1Loop(approximation, tolerance, approximationValue, iterations, polynomial) + while abs(polynomial(approximation(3))) > tolerance + [approximation, approximationValue, iterations] = insideLoop(approximation, approximationValue, polynomial, iterations); + end +end + +function [approximation, approximationValue, iterations] = insideLoop(approximation, approximationValue, polynomial, iterations) + equationsSystem = createEquationSystem(approximation, approximationValue); + [zPlus, zMinus] = rootsOfQuadraticFormula(equationsSystem, approximationValue); + [approximation, approximationValue, iterations] = updateApproximations(zPlus, zMinus, approximation, iterations, polynomial); +end + +function equationsSystem = createEquationSystem(approximation, approximationValue) + [z0, z1, difference0, difference1] = initializeEquationSystem(approximation, approximationValue); + equationsSystem = solveEquationSystem(z0, difference0, z1, difference1); +end + +function [zPlus, zMinus] = rootsOfQuadraticFormula(equationsSystem, approximationValue) + [a, b, c] = createApproximatedQuadraticFormula(equationsSystem, approximationValue); + [zPlus, zMinus] = findRootsOfQuadraticFormula(a, b, c); +end + +function [approximation, approximationValue, iterations] = updateApproximations(zPlus, zMinus, approximation, iterations, polynomial) + newApproximation = chooseNewRoot(zPlus, zMinus, approximation); + iterations = addZeroToIterationVector(newApproximation, iterations, polynomial); + worstApproximationIndex = getWorstApproximationIndex(approximation, newApproximation); + [approximation, approximationValue] = deleteWorstApproximation(worstApproximationIndex, approximation, polynomial, newApproximation); +end + +function [z0, z1, difference0, difference1] = initializeEquationSystem(approximation, approximationValue) + z0 = approximation(1) - approximation(3); + z1 = approximation(2) - approximation(3); + difference0 = approximationValue(1) - approximationValue(3); + difference1 = approximationValue(2) - approximationValue(3); +end + +function equationsSystem = solveEquationSystem(z0, difference0, z1, difference1) + equationsSystem = [z0 ^ 2, z0, difference0; z1 ^ 2, z1, difference1]; + reductor = equationsSystem(2, 1) / equationsSystem(1, 1); + equationsSystem(2, :) = equationsSystem(2, :) - reductor * equationsSystem(1, :); + equationsSystem(2, 1) = 0; + equationsSystem(2, :) = equationsSystem(2, :) ./ equationsSystem(2, 2); + equationsSystem(1, :) = equationsSystem(1, :) - equationsSystem(1, 2) * equationsSystem(2, :); + equationsSystem(1, :) = equationsSystem(1, :) ./ equationsSystem(1, 1); +end + +function [a, b, c] = createApproximatedQuadraticFormula(equationsSystem, approximationValue) + a = equationsSystem(1, 3); + b = equationsSystem(2, 3); + c = approximationValue(3); +end + +function [zPlus, zMinus] = findRootsOfQuadraticFormula(a, b, c) + zPlus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c)); + zMinus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c)); +end + +function newApproximation = chooseNewRoot(zPlus, zMinus, approximation) + if abs(zPlus) < abs(zMinus) + newApproximation = approximation(3) + zPlus; + else + newApproximation = approximation(3) + zMinus; + end +end + +function iterations = addZeroToIterationVector(newApproximation, iterations, polynomial) + zero = newApproximation; + iterations(:, size(iterations, 2) + 1) = [zero, polynomial(zero)]; +end + +function worstApproximationIndex = getWorstApproximationIndex(approximation, newApproximation) + worstApproximationIndex = -1; + worstApproximationDifference = 0; + for i = 1:size(approximation, 2) + diff = abs(approximation(i) - newApproximation); + if diff > worstApproximationDifference + worstApproximationIndex = i; + worstApproximationDifference = diff; + end + end +end + +function [approximation, approximationValue] = deleteWorstApproximation(worstApproximationIndex, approximation, polynomial, newApproximation) + approximation(worstApproximationIndex) = []; + approximation(3) = newApproximation; + approximationValue = arrayfun(polynomial, approximation); +end \ No newline at end of file diff --git a/ENUME/projectB/Code/task2MM2.m b/ENUME/projectB/Code/task2MM2.m new file mode 100644 index 00000000..449c9ad9 --- /dev/null +++ b/ENUME/projectB/Code/task2MM2.m @@ -0,0 +1,47 @@ +interval = [-5, 10]; +rootBrackets = rootBracketing(@polynomial, interval(1), interval(2)); + +printGraph(@polynomial, 'MM2', @mm2, interval, rootBrackets, 'Approximate zeros of function for method of '); + +printComplexGraph(@polynomial, 'MM2', @mm2, [-1+i, 0], 'Aproximate complex roots of polynomial'); + +% the polynomial function for task 2 +function y = polynomial(x) + y = -2 * x^4 + 12 * x^3 + 4* x^2 + 1 * x + 3; +end + +% find roots of polynomial using MM2 +function [approx, steps] = mm2(func, a, b, tolerance) + % define current and (dummy) previous approximation point + approx = (a + b) / 2; + + % initialize output + steps = [approx; func(approx)]; + + % iterate algorithm until the error is within tolerance + % the error is defined as the diff between the prev and the current approx + + func(approx) + while abs(func(approx)) > tolerance + % calculate approximating parabola using first and second derivative + c = func(approx); + b = deriv(func, approx, 1); + a = deriv(func, approx, 2) / 2; + + % find roots of parabola + zplus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c)); + zminus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c)); + + % choose root closer to current approximation + if abs(zplus) < abs(zminus) + newapprox = approx + zplus; + else + newapprox = approx + zminus; + end + + % update answer and prev approx + prevapprox = approx; + approx = newapprox; + steps(:, size(steps, 2) + 1) = [approx, func(approx)]; + end +end diff --git a/ENUME/projectB/Code/task2muller.m b/ENUME/projectB/Code/task2muller.m new file mode 100644 index 00000000..c72bfc1b --- /dev/null +++ b/ENUME/projectB/Code/task2muller.m @@ -0,0 +1,114 @@ +% define available algorithms +algorithms = { + 'MM1', @mm1; + 'MM2', @mm2 +}; + +% find all real root brackets +interval = [1, 7]; +brackets = rootbrac(@polynomial, interval(1), interval(2)); + +% find and graph real roots using both algorithms +printroots(@polynomial, algorithms, interval, brackets, ... + 'Approximate real roots of polynomial', 'realroots'); +printcomplex(@polynomial, algorithms, [-1+i, 0], ... + 'Approximate complex roots of polynomial', 'complexroots'); + +% find roots of polynomial using MM1 +function [zero, steps] = mm1(func, a, b, tolerance) + % define the three approximation points + apprx = [a, b, (a + b) / 2]; + apprxval = arrayfun(func, apprx); + + % initialize output + steps = [apprx(3); func(apprx(3))]; + + % iterate algorithm until the error is within tolerance + while abs(apprx(3) - apprx(2)) > tolerance + % prepare linear equation system to find parabola + z0 = apprx(1) - apprx(3); + z1 = apprx(2) - apprx(3); + diff0 = apprxval(1) - apprxval(3); + diff1 = apprxval(2) - apprxval(3); + + % solve equation system using Gaussian elimination (spaghetti code but fast) + eqsys = [z0 ^ 2, z0, diff0; z1 ^ 2, z1, diff1]; + reductor = eqsys(2, 1) / eqsys(1, 1); + eqsys(2, :) = eqsys(2, :) - reductor * eqsys(1, :); + eqsys(2, 1) = 0; + eqsys(2, :) = eqsys(2, :) ./ eqsys(2, 2); + eqsys(1, :) = eqsys(1, :) - eqsys(1, 2) * eqsys(2, :); + eqsys(1, :) = eqsys(1, :) ./ eqsys(1, 1); + + % define approximation parabola + a = eqsys(1, 3); + b = eqsys(2, 3); + c = apprxval(3); + + % find roots of parabola + zplus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c)); + zminus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c)); + + % choose root closer to current approximation + if abs(zplus) < abs(zminus) + newapprx = apprx(3) + zplus; + else + newapprx = apprx(3) + zminus; + end + + % update answer + zero = newapprx; + steps(:, size(steps, 2) + 1) = [zero, func(zero)]; + + % eliminate the most distant of the three approximations + worstapprxindex = -1; + worstapprxdiff = 0; + for i = 1:size(apprx, 2) + diff = abs(apprx(i) - newapprx); + if diff > worstapprxdiff + worstapprxindex = i; + worstapprxdiff = diff; + end + end + + % delete old approximation and append new one + apprx(worstapprxindex) = []; + apprx(3) = newapprx; + apprxval = arrayfun(func, apprx); + end +end + +% find roots of polynomial using MM2 +function [approx, steps] = mm2(func, a, b, tolerance) + % define current and (dummy) previous approximation point + approx = (a + b) / 2; + prevapprox = approx + b - a; + + % initialize output + steps = [approx; func(approx)]; + + % iterate algorithm until the error is within tolerance + % the error is defined as the diff between the prev and the current approx + while abs(approx - prevapprox) > tolerance + % calculate approximating parabola using first and second derivative + c = func(approx); + b = deriv(func, approx, 1); + a = deriv(func, approx, 2) / 2; + + % find roots of parabola + zplus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c)); + zminus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c)); + + % choose root closer to current approximation + if abs(zplus) < abs(zminus) + newapprox = approx + zplus; + else + newapprox = approx + zminus; + end + + % update answer and prev approx + prevapprox = approx; + approx = newapprox; + steps(:, size(steps, 2) + 1) = [approx, func(approx)]; + end +end