Skip to content
Snippets Groups Projects
Dynamics_Model.m 17.24 KiB
classdef Dynamics_Model < matlab.mixin.Copyable %handle
    properties
        num_dim_Y
                
        interpolant_XY
        
        sigma_estimation
        sigma_test
        alpha_initial
        initial_estimate_X
        
        X
        T
        Y
        previous_N_fixed
        N_fixed
        nb_times_fixed
        
        current_alpha
        alpha_variable
        confidence
        window_size
        
        display_screen
        marginal_X_Yi
        limits_Yi
    end
    methods
        function obj = Dynamics_Model(filename_interpolant, display_screen)
            obj.display_screen = display_screen;
            if obj.display_screen ~= -1
                figure(display_screen)
                clf(display_screen)
            end
            
            structure = load(filename_interpolant);

            obj.interpolant_XY = structure.interpolant_XY;
            
            obj.num_dim_Y = size(structure.interpolant_Y.GridVectors,2);
            
            N = size(structure.interpolant_Y.GridVectors{1}, 2);
            for i=1:obj.num_dim_Y
                obj.limits_Yi(i,1) = structure.interpolant_Y.GridVectors{i}(1);
                obj.limits_Yi(i,2) = structure.interpolant_Y.GridVectors{i}(N);
            end
            
            for i=1:obj.num_dim_Y
                obj.marginal_X_Yi(:,:,i) = flipdim(structure.P_Yi_knowing_X(:,:,i),1);
            end
        end
        function initialise(obj, initial_X, alpha_ini, sigma_estimation, sigma_test)
            obj.T = [];
            obj.X = [];
            obj.Y = [];
            obj.N_fixed = 0;
            obj.current_alpha = alpha_ini;
            obj.alpha_variable = [];
            obj.window_size = [];
            obj.confidence = [];
            obj.nb_times_fixed = [];
            
            obj.initial_estimate_X = initial_X;
            obj.alpha_initial = alpha_ini;
            obj.sigma_estimation = sigma_estimation;
            obj.sigma_test = sigma_test;
        end
        function process_new_frame(obj, Yt, Tt)
            obj.T = [obj.T; Tt];
            obj.Y = [obj.Y; Yt(:,1:obj.num_dim_Y)];
            frame = size(obj.T,1);
            
            % estimate alpha and adjust the window size
            alpha = obj.estimate_alpha();
            sprintf('estimated alpha_variable: %f', alpha);
            obj.current_alpha = alpha;
            obj.window_size = [obj.window_size, frame - obj.N_fixed];
            
            % estimate X inside the window (and update N_fixed)
            obj.previous_N_fixed = obj.N_fixed;
            obj.estimate_X(alpha);
            sprintf('"normalised" log likelihood of X (or confidence): %f', obj.confidence(frame));
            if obj.display_screen ~= -1
                obj.plot_estimated_X();
            end
            
            % save the value of alpha for the frames that have converged
            if obj.previous_N_fixed < obj.N_fixed
                for i=obj.previous_N_fixed+1:obj.N_fixed
                    obj.alpha_variable(i) = alpha;
                end
            end
        end
        function alpha = estimate_alpha(obj)
            N = size(obj.X,1);
            
            if N < 5
                alpha = obj.alpha_initial;
                return
            end
            
            first_index = max(obj.N_fixed, 1);
            nb_points = N - first_index + 1;
            
            if nb_points < 3 % we need at least 2 intervals to compute the mean
                alpha = obj.alpha_initial;
            else
                X_2_to_N = obj.X(first_index+1:N);
                X_1_to_Nminus1 = obj.X(first_index:N-1);
                T_2_to_N = obj.T(first_index+1:N);
                T_1_to_Nminus1 = obj.T(first_index:N-1);

                delta_X = X_2_to_N - X_1_to_Nminus1;
                delta_T = T_2_to_N - T_1_to_Nminus1;

                factors = delta_X ./ delta_T;

                alpha = mean(factors);

                if alpha <= 0.9 * obj.alpha_initial; %0.75 %0.015  0.75%0.85%0.9
                    alpha = 0.9 * obj.alpha_initial; %0.75%0.015;%0.85%0.9
                end
                if alpha >= 1.1 * obj.alpha_initial; %1.25%0.015  1.25%1.15%1.1
                    alpha = 1.1 * obj.alpha_initial; %1.25%0.015;%1.15%1.1
                end
%                     if alpha <= 0.015
%                         alpha = 0.015;
%                     end
                    
%                     if alpha > 0.025
%                         alpha = 0.025;
%                     end
            end
        end
        function estimate_X(obj, alpha)
            if obj.N_fixed > 0
                last_fixed_X = obj.X(obj.N_fixed);
            else
                last_fixed_X = obj.initial_estimate_X;
            end

            %function to be minimised over new_X, with extra parameters Y, alpha and T
            f = @(variable_X)(-obj.logP_x_knowing_y_partialUpdate(last_fixed_X,variable_X,alpha,obj.sigma_estimation));

            N = size(obj.X,1);

            if N > obj.N_fixed
                X_ini = obj.X(obj.N_fixed+1:N);
            else
                X_ini = [];
            end

            if N == 0
                new_X_ini = obj.initial_estimate_X;
            elseif N == 1
                new_X_ini = obj.X(N) + alpha;
            else
                new_X_ini = obj.X(N) + alpha * (obj.T(N+1) - obj.T(N));
            end
% voir pb donc effacer X_ini=obj.normalise_X(X_ini)
            X_ini = [X_ini; new_X_ini];
            X_ini=obj.normalise_X(X_ini)

            lb = repmat(0,1,length(X_ini));
            ub = repmat(1,1,length(X_ini));
            A = [];
            b = [];
            Aeq = [];
            beq = [];
            [new_X_variable,loglikelihood] = fmincon(f,X_ini,A,b,Aeq,beq,lb,ub);
            obj.confidence = [obj.confidence, -loglikelihood / size(new_X_variable,1)];
            
            new_X_variable = obj.normalise_X(new_X_variable);

            new_X = [obj.X(1:obj.N_fixed); new_X_variable];

            % comparer X_estimated et X_0 et noter ceux qui ne bougent plus
            % et ceux qui bougent encore

            candidates_new_N_fixed = [];

            for i = obj.N_fixed + 1 : N
                while i > size(obj.nb_times_fixed,1)
                    obj.nb_times_fixed = [obj.nb_times_fixed; 0];
                end
                
                if abs(obj.X(i) - new_X(i)) < 1e-3%1e-2
                    obj.nb_times_fixed(i) = obj.nb_times_fixed(i)+1;
                else
                    obj.nb_times_fixed(i) = 0;
                end

                if obj.nb_times_fixed(i) >= 2
                    candidates_new_N_fixed = [candidates_new_N_fixed i];
                end
            end

            new_N_fixed = obj.N_fixed;
            i = obj.N_fixed + 1;
            for j=1:size(candidates_new_N_fixed,2)
                if i ~= candidates_new_N_fixed(j)
                    break;
                end
                new_N_fixed = i;
                i = i+1;
            end

            if new_N_fixed > N-3
                new_N_fixed = N-3;
            end
% 
            if new_N_fixed < 0
                new_N_fixed = 0;
            end
% 
            if new_N_fixed < N-13 %N-8
                new_N_fixed = N-13; %N-8;
            end
            
            if size(new_X, 1) < 4 %12
                new_N_fixed = size(new_X, 1) - 2;
                if new_N_fixed < 0
                    new_N_fixed = 0;
                end
            elseif size(new_X, 1) == 4 %12
                new_N_fixed = 0;
            end

            obj.N_fixed = new_N_fixed;
            obj.X = new_X;
        end
        function spread_X(obj)
            N = size(obj.X,1);
            
            if N ==1
                obj.X = 0;
                obj.confidence = 1;
                obj.current_alpha = obj.alpha_initial;
            
                obj.plot_estimated_X()
                obj.compute_loglikelihood_dynamics_forced(1:N)
                return
            elseif N == 2
                obj.X = [0 1];
                obj.confidence = [0 1];
                obj.current_alpha = 1;
            
                obj.plot_estimated_X()
                obj.compute_loglikelihood_dynamics_forced(1:N)
                return
            end
            
            X_tmp = 0:1/(N-1):1;
            X_2_to_N = X_tmp(2:N)';
            X_1_to_Nminus1 = X_tmp(1:N-1)';
            T_2_to_N = obj.T(2:N);
            T_1_to_Nminus1 = obj.T(1:N-1);

            delta_X = X_2_to_N - X_1_to_Nminus1;
            delta_T = T_2_to_N - T_1_to_Nminus1;

            factors = delta_X ./ delta_T;
            alpha = mean(factors);
            

            %function to be minimised over new_X, with extra parameters Y, alpha and T
            f = @(variable_X)(-obj.logP_x_knowing_y_spread(variable_X,alpha,obj.sigma_estimation));

            
            X_ini = X_tmp(2:end-1)';
            lb = repmat(0,1,length(X_ini));
            ub = repmat(1,1,length(X_ini));
            A = [];
            b = [];
            Aeq = [];
            beq = [];
            [new_X,loglikelihood] = fmincon(f,X_ini,A,b,Aeq,beq,lb,ub);
            
            new_X = [0; obj.normalise_X(new_X); 1];
            obj.X = new_X;
            obj.confidence = [1, -loglikelihood / size(new_X,1), 1];
            
            
            
            X_2_to_N = obj.X(2:N);
            X_1_to_Nminus1 = obj.X(1:N-1);
            T_2_to_N = obj.T(2:N);
            T_1_to_Nminus1 = obj.T(1:N-1);

            delta_X = X_2_to_N - X_1_to_Nminus1;
            delta_T = T_2_to_N - T_1_to_Nminus1;

            factors = delta_X ./ delta_T;
            obj.current_alpha = mean(factors);
            
            obj.plot_estimated_X()
            obj.compute_loglikelihood_dynamics_forced(1:N)
        end
        function loglikelihood = logP_x_knowing_y_partialUpdate(obj, last_fixed_X, variable_X, alpha, sigma)
            N_variable = size(variable_X,1);

 %           variable_X = obj.normalise_X(variable_X);

            % if N == 1, we only maximise P_cond_y(Y(1),X(1))
            % if N == 2, we maximise P_cond_y(Y(2),X(2)) * P_x_Markov_simple(X(2),X(1)) * P_cond_y(Y(1),X(1)) with P_x_Markov_simple(X(2),X(1)) = 0 if delta_X is negative, and uniform proba otherwise

            if obj.N_fixed == 0
                loglikelihood = obj.logP_cond_y(obj.Y(1,:),variable_X(1));
            else
                loglikelihood = obj.logP_cond_y(obj.Y(obj.N_fixed+1,:),variable_X(1)) + obj.logP_x_Markov(variable_X(1),last_fixed_X,obj.T(obj.N_fixed+1),obj.T(obj.N_fixed),alpha,sigma);
            end

            if N_variable > 1
                Y_2_to_N = obj.Y(obj.N_fixed+2:obj.N_fixed+N_variable,:);
                X_2_to_N = variable_X(2:N_variable);
                X_1_to_Nminus1 = variable_X(1:N_variable-1);
                T_2_to_N = obj.T(obj.N_fixed+2:obj.N_fixed+N_variable);
                T_1_to_Nminus1 = obj.T(obj.N_fixed+1:obj.N_fixed+N_variable-1);

                ll_proba_cond_y = obj.logP_cond_y(Y_2_to_N, X_2_to_N);
                ll_proba_x_Markov = obj.logP_x_Markov(X_2_to_N,X_1_to_Nminus1,T_2_to_N,T_1_to_Nminus1,alpha,sigma);
                vect_tmp = ll_proba_cond_y + ll_proba_x_Markov;

                loglikelihood = loglikelihood + sum(vect_tmp);
            end
        end
        function loglikelihood = logP_x_knowing_y_spread(obj, variable_X, alpha, sigma)
            N_variable = size(variable_X,1);

            % we maximise P_cond_y(Y(1),0) * P_x_Markov_simple(X(2),0) * P_cond_y(Y(i),X(i)) * P_x_Markov_simple(X(i+1),X(i)) * P_x_Markov_simple(1,X(N-1)) * P_cond_y(Y(N),1)

            loglikelihood = obj.logP_cond_y(obj.Y(1,:),0) + obj.logP_x_Markov(variable_X(1),0,obj.T(2),obj.T(1),alpha,sigma);
            loglikelihood = loglikelihood + sum(obj.logP_cond_y(obj.Y(2:end-1,:), variable_X));
            loglikelihood = loglikelihood + obj.logP_x_Markov(1, variable_X(end),obj.T(end),obj.T(end-1),alpha,sigma);
            loglikelihood = loglikelihood + obj.logP_cond_y(obj.Y(end,:),1);
            
            if N_variable > 1
                ll_proba_x_Markov = obj.logP_x_Markov(variable_X(2:end),variable_X(1:end-1),obj.T(3:end-1),obj.T(2:end-2),alpha,sigma);
                loglikelihood = loglikelihood + sum(ll_proba_x_Markov);
            end
        end
        function loglikelihood = logP_cond_y(obj, Yi, Xi)
            s = size(Yi,1);
            comp_small = repmat(obj.limits_Yi(:,1)',s,1);
            comp_big = repmat(obj.limits_Yi(:,2)',s,1);
            
            too_small = Yi < comp_small;
            too_big = Yi > comp_big;
            
            Yi(too_small) = comp_small(too_small);
            Yi(too_big) = comp_big(too_big);
            
            xy = [obj.normalise_X(Xi) Yi];
            
            if isempty(xy)
                loglikelihood = [];
                return;
            end
            
            loglikelihood = log(obj.interpolant_XY(xy));
        end
        function loglikelihood = logP_x_Markov(obj, Xi, Xim, Ti, Tim, alpha, sigma)
            
            difference = (Xi - Xim) - alpha .* (Ti - Tim);

            % penalise negative and null dX
            indexes = Xi - Xim < 0;
            if length(alpha) > 1
                difference(indexes) = 5 * (Xi(indexes) - Xim(indexes)) - alpha(indexes) .* (Ti(indexes) - Tim(indexes));
            else
                difference(indexes) = 5 * (Xi(indexes) - Xim(indexes)) - alpha .* (Ti(indexes) - Tim(indexes));
            end

            if isempty(difference)
                loglikelihood = -100;
            else
                loglikelihood = log(normpdf(difference,0,sigma));

                index2 = loglikelihood == -Inf;%a été supprimé
                loglikelihood(index2) = -100;%a été supprimé
            end
        end
        function list_frames = get_converged_frames(obj)
            if obj.previous_N_fixed < obj.N_fixed
                list_frames = [obj.previous_N_fixed+1:obj.N_fixed];
            else
                list_frames = [];
            end
        end
        
        function llh_dynamics = compute_loglikelihood_dynamics_forced(obj, frames)
            %llh_dynamics(frames <= 1) = nan;
            
            indexes = frames > 1 & frames <= length(obj.T);
            
%             if ~isempty(obj.alpha_variable)
%                 alpha = obj.alpha_variable(end);
%             else
%                 alpha = obj.current_alpha;
%             end
            alpha = obj.current_alpha;
            
            terme1 = obj.logP_cond_y(obj.Y(frames(indexes),:), obj.X(frames(indexes)));
            terme2 = obj.logP_x_Markov(obj.X(frames(indexes)),obj.X(frames(indexes)-1),obj.T(frames(indexes)),obj.T(frames(indexes)-1),alpha,obj.sigma_test);
            llh_dynamics(indexes) = terme1 + terme2;
            
            indexes = frames <= 1
            frames(indexes)
            terme1 = obj.logP_cond_y(obj.Y(frames(indexes),:), obj.X(frames(indexes)));
            %llh_dynamics(frames <= 1) = terme1 + obj.logP_x_Markov(obj.alpha_initial, 0, 2, 1, obj.alpha_initial, obj.sigma_test);
            llh_dynamics(frames <= 1) = terme1 + obj.logP_x_Markov(obj.X(1), obj.X(1)-alpha, 2, 1, alpha, obj.sigma_test);
        end
        function plot_estimated_X(obj)
            if obj.display_screen ~= -1
                N = size(obj.X,1);
                start_frame = max(N - 50, 1);
                
                figure(obj.display_screen)
                
                
                for i=1:obj.num_dim_Y
                    subplot(obj.num_dim_Y,1,i)
                    hold off
                    imagesc([0 1],[obj.limits_Yi(i,1) obj.limits_Yi(i,2)],obj.marginal_X_Yi(:,:,i),'CDataMapping','scaled')
                    set(gca,'YDir','normal')
                    title(['Likelihood of (X,Y_' i ') to be normal (color plot) and estimated (X,Y_' i ') (black crosses)'])
                    xlabel('Percentage of movement completion X')
                    ylabel(['Manifold coordinate Y_' i])
                    hold on
                    plot(obj.normalise_X(obj.X(start_frame:N)),obj.Y(start_frame:N,i),'kx')
                    
                end
                %pour faire des gifs
                %saveas(obj.display_screen, strcat('estimatedX_frame', int2str(N), '.png'))
            end

        end

        function [im]=final_plot_estimated_X(obj)
            if obj.display_screen ~= -1
                N = size(obj.X,1);
                start_frame = max(N - 50, 1);
                
                figure(obj.display_screen)
                
                
                for i=1:obj.num_dim_Y
                    subplot(obj.num_dim_Y,1,i)
                    hold off
                    im=imagesc([0 1],[obj.limits_Yi(i,1) obj.limits_Yi(i,2)],obj.marginal_X_Yi(:,:,i),'CDataMapping','scaled')
                    %set(gca,'YDir','normal')
                    hold on
                    plot(obj.normalise_X(obj.X(start_frame:N)),obj.Y(start_frame:N,i),'kx')
                    axis off
                    
                end
                %pour faire des gifs
                %saveas(obj.display_screen, strcat('estimatedX_frame', int2str(N), '.png'))
            end
        end

        function X = normalise_X(obj, X)
            X(X<0) = 0;
            X(X>1) = 1;
        end
        function periodic = is_periodic(obj)
            periodic = 0;
        end
    end
    
    %methods (Abstract)
    %    X = normalise_X(obj, X)
    %    periodic = is_periodic(obj)
    %end
end