classdef HW7_Solution_GoldenSection < handle
    %HW7_GoldenRatio Find minimum of fucntion using Golden Section search
    %   Detailed explanation goes here
    
    properties
        F;                  %Function Handlde
        X;                  %Current intervals (3 x 1);
        FX;                 %Function Evalulated at X
        TolX=.001;          %Tolerance for stopping
        R=(1+sqrt(5))/2;    %Default Ratio (Golden)
        Found;              %Found minimum
        NFunctionCalls;     %Number of function calls required to find minimum
    end
    
    methods
        
        function findMin(obj)
            
            %Interval size used to check convergence
            dX=obj.X(3)-obj.X(1);
            
            %Calculate the function at the initial X values
            obj.FX(1)=obj.F(obj.X(1));
            obj.FX(2)=obj.F(obj.X(2));
            obj.FX(3)=obj.F(obj.X(3));
            
            %Number of function calls (Three from above)
            N=3;
            
            %Loop until interval size is below tolerance. 
            while dX>obj.TolX
                
                %Get new interval
                [ X_out,FX_out ] = obj.updateGRInterval(obj.X,obj.FX);
                
                %Calculate new interval size
                dX=X_out(3)-X_out(1);
                
                %update X and Function values
                obj.X=X_out;
                obj.FX=FX_out;
                
                %update number of function calls. 
                N=N+1;
            end
            
            %Set these object properties
            obj.Found=(obj.X(3)+obj.X(1))/2;
            obj.NFunctionCalls=N;
            
        end
        
        function [ X_out,FX_out ] = updateGRInterval(obj,X,FX)
            
            f=obj.F;
            
            %Ratio of lengths of interval (a/b)
            % |-----a-----|--b--|
            R=obj.R;
            
            % a/(a+b) is:
            r=R/(1+R);
            
            %Find if the large interval is on right or left
            if (X(2)-X(1)) > (X(3)-X(2))
                %X1-----X2---X3
                IntSide='Left';
            else
                %X1---X2-----X3
                IntSide='Right';
            end
            
            switch IntSide
                case 'Left'
                    %X1---Xnew--X2---X3
                    
                    %Find new X position
                    IntSize=X(2)-X(1); %large interval size
                    Xnew=X(1)+IntSize*r;
                    %Evaulate function at Xnew
                    F_Xnew=f(Xnew);
                    
                    %Return new interval X and FX depending on F_Xnew
                    if F_Xnew<FX(2)  %use left interval
                        X_out(1)=X(1);
                        X_out(2)=Xnew;
                        X_out(3)=X(2);
                        FX_out(1)=FX(1);
                        FX_out(2)=F_Xnew;
                        FX_out(3)=FX(2);
                    else    %use right interval
                        X_out(1)=Xnew;
                        X_out(2)=X(2);
                        X_out(3)=X(3);
                        FX_out(1)=F_Xnew;
                        FX_out(2)=FX(2);
                        FX_out(3)=FX(3);
                    end
                    
                case 'Right'
                    
                    %X1---X2--Xnew---X3
                    
                    %Find new X position
                    IntSize=X(3)-X(2); %large interval size
                    Xnew=X(2)+IntSize*(1-r);
                    %Evaulate function at Xnew
                    F_Xnew=f(Xnew);
                    
                    %Return new interval X and FX depending on F_Xnew
                    if F_Xnew<FX(2)  %use right interval
                        X_out(1)=X(2);
                        X_out(2)=Xnew;
                        X_out(3)=X(3);
                        FX_out(1)=FX(2);
                        FX_out(2)=F_Xnew;
                        FX_out(3)=FX(3);
                    else    %use left interval
                        X_out(1)=X(1);
                        X_out(2)=X(2);
                        X_out(3)=Xnew;
                        FX_out(1)=FX(1);
                        FX_out(2)=FX(2);
                        FX_out(3)=F_Xnew;
                    end
            end  
        end
        
        
        function plotUpdateGS(obj,PauseTime)
            
            
            %This is similar to findMin() but shows updates. 
            
            if nargin<2
                PauseTime=1;
            end
              
            dX=obj.X(3)-obj.X(1);
            obj.FX(1)=obj.F(obj.X(1));
            obj.FX(2)=obj.F(obj.X(2));
            obj.FX(3)=obj.F(obj.X(3));
            
            GrayOut=0;
            
            %Plot function over interval
            Xvec=linspace(obj.X(1),obj.X(3),100);
            Yvec=obj.F(Xvec);

            figure
            plot(Xvec,Yvec,'r')
            hold on
            xlabel('x')
            ylabel('f(x)')
            
            while dX>obj.TolX
                
                if GrayOut %so it doesn't try to do this the first time
                    for jj=1:3
                        PobjVec(jj).Color=[.75,.75,.75];
                    end
                else
                    GrayOut=1;
                end
                
                %Plot the new intervals
                for jj=1:3
                    PobjVec(jj)=plot([obj.X(jj) obj.X(jj)],[min(Yvec) max(Yvec)],'k--');
                end
                
                %Update the intervals
                [ X_out,FX_out ] = obj.updateGRInterval(obj.X,obj.FX);
                dX=X_out(3)-X_out(1);
                obj.X=X_out;
                obj.FX=FX_out;
                
                %pause so we can see update
                pause(PauseTime)
            end
        end
        
        
    end
    
end

