wolffd@0: % --- wolffd@0: % class ClipSimGraphMD wolffd@0: % Directed graph representing comparative clip similarities. wolffd@0: % EACH pair of vertices has just ONE directed edge connecting them wolffd@0: % wolffd@0: % each node represents a pair of clips, wolffd@0: % an edge (a,b) -> (a,c) is present if there is at least one wolffd@0: % users judging clip a more similar to clip b than to clip c wolffd@0: % wolffd@0: % The Edges thus represent the (are nearer to each othen than) wolffd@0: % expression wolffd@0: % --- wolffd@0: wolffd@0: classdef ClipSimGraphMD < ClipSimGraph & handle wolffd@0: wolffd@0: wolffd@0: properties wolffd@0: wolffd@0: % --- wolffd@0: % History of edge weights, is a nodes x nodes cell. wolffd@0: % wolffd@0: % E_hist(i,j) = m x 2 Matrix containing wolffd@0: % Pair of information for each set [votes votes_complete] wolffd@0: hE; % History of edge weights wolffd@0: end wolffd@0: wolffd@0: % --- wolffd@0: % the methods wolffd@0: % --- wolffd@0: methods wolffd@0: wolffd@0: % constructor of the graph wolffd@0: function G = ClipSimGraphMD(comparison, comparison_ids) wolffd@0: wolffd@0: if nargin == 0 wolffd@0: % --- wolffd@0: % empty constructor wolffd@0: % --- wolffd@0: wolffd@0: elseif nargin == 1 wolffd@0: % todo: copy graph wolffd@0: wolffd@0: elseif nargin == 2 wolffd@0: wolffd@0: wolffd@0: % --- wolffd@0: % handle automatic or manual input wolffd@0: % --- wolffd@0: for i = 1:size(comparison,1) wolffd@0: wolffd@0: % get clips and votes wolffd@0: clips = comparison_ids(comparison(i,1:3)); wolffd@0: votes = comparison(i,4:6); wolffd@0: wolffd@0: % for each triplet position create an edge reflecting the wolffd@0: % absolute and relative voting for this position wolffd@0: wolffd@0: % --- wolffd@0: % NOTE: we index 0 - 2 to ease the mod wolffd@0: % calculaton for the remaining indices wolffd@0: % --- wolffd@0: for v = 0:2 wolffd@0: wolffd@0: % --- wolffd@0: % has at least one user voted this clip out? wolffd@0: % If so, treat it as an outlier and determine score wolffd@0: % --- wolffd@0: if votes(v+1) > 0 wolffd@0: wolffd@0: a = mod(v+1, 3)+1; wolffd@0: b = mod(v+2, 3)+1; wolffd@0: c = v+1; wolffd@0: wolffd@0: wolffd@0: % --- wolffd@0: % every outlier vote results in two wolffd@0: % dissimilarity equations, favored by wolffd@0: % the people who voted for the outlier wolffd@0: % --- wolffd@0: wolffd@0: % edge 1 wolffd@0: add_edge(G, clips(a), clips(b), clips(c), votes(v+1), sum(votes)); wolffd@0: wolffd@0: % edge 2 wolffd@0: add_edge(G, clips(b), clips(a), clips(c), votes(v+1), sum(votes)); wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % end constructor function wolffd@0: end wolffd@0: wolffd@0: % adds a node stating clip a is more near % wolffd@0: % to clip b then clip c wolffd@0: function Vid = add_node(G, a, b) wolffd@0: wolffd@0: Vid = add_node@ClipSimGraph(G, a, b); wolffd@0: wolffd@0: G.hE{Vid,Vid} = []; wolffd@0: wolffd@0: end wolffd@0: wolffd@0: function remove_node(G, a, b) wolffd@0: wolffd@0: if nargin == 3 wolffd@0: wolffd@0: V1 = G.node(a, b); wolffd@0: elseif nargin == 2 wolffd@0: wolffd@0: V1 = a; wolffd@0: end wolffd@0: wolffd@0: if ~isempty(Vid) wolffd@0: wolffd@0: % --- wolffd@0: % look for edges connected to Vid wolffd@0: % and delete their histograms wolffd@0: % --- wolffd@0: G.hE(:,Vid) = []; wolffd@0: G.hE(Vid,:) = []; wolffd@0: wolffd@0: % --- wolffd@0: % TODO: Efficiently Remove the actual node from the wolffd@0: % GRAPH wolffd@0: % --- wolffd@0: G.Vclips(Vid,:) = []; wolffd@0: wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % --- wolffd@0: % add an edge saying sim(a,b) > sim(a,c) wolffd@0: % --- wolffd@0: function add_edge(G, a, b, c, votes, allvotes) wolffd@0: wolffd@0: V1 = add_node(G, a, b); wolffd@0: V2 = add_node(G, a, c); wolffd@0: wolffd@0: % --- wolffd@0: % save new weight values into histogram wolffd@0: % --- wolffd@0: if isempty(G.hE(V1, V2)) wolffd@0: wolffd@0: G.hE{V1,V2} = [votes allvotes]; wolffd@0: else wolffd@0: G.hE{V1,V2} = [G.hE{V1,V2}; votes allvotes]; wolffd@0: end wolffd@0: wolffd@0: % --- wolffd@0: % update Edges wolffd@0: % --- wolffd@0: G.update_E(a, b, c); wolffd@0: wolffd@0: end wolffd@0: wolffd@0: function remove_edge(G, a, b, c) wolffd@0: wolffd@0: if nargin == 4 wolffd@0: wolffd@0: V1 = G.node(a, b); wolffd@0: V2 = G.node(a, c); wolffd@0: elseif nargin == 3 wolffd@0: wolffd@0: V1 = a; wolffd@0: V2 = b; wolffd@0: end wolffd@0: wolffd@0: if ~isempty(V1) && ~isempty(V2) wolffd@0: wolffd@0: % set Edge to zero wolffd@0: G.hE{V1, V2} = []; wolffd@0: else wolffd@0: wolffd@0: error 'nodes not found'; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % --- wolffd@0: % updates the edge weight given 3 clip ids or wolffd@0: % two nodes, based on the edges history wolffd@0: % wolffd@0: % The specified (V1,V2) and the symmetric edges' (V2,V1) weights wolffd@0: % are evaluated and the stronger edge will get wolffd@0: % the excessive weight while the loosing edge wolffd@0: % will be deleted wolffd@0: % --- wolffd@0: function update_E(G, a, b, c) wolffd@0: % update_E(G, a, b, c) wolffd@0: % update_E(G, V1, V2) wolffd@0: wolffd@0: % determine the type of input parameters wolffd@0: if nargin == 4 wolffd@0: wolffd@0: V1 = G.node(a, b); wolffd@0: V2 = G.node(a, c); wolffd@0: elseif nargin == 3 wolffd@0: wolffd@0: V1 = a; wolffd@0: V2 = b; wolffd@0: end wolffd@0: wolffd@0: % --- wolffd@0: % calculate weighted sum for specified edge wolffd@0: % and for symmetric edge wolffd@0: % --- wolffd@0: thisw = unbal_edge_weight(G, V1, V2); wolffd@0: symmw = unbal_edge_weight(G, V2, V1); wolffd@0: wolffd@0: % --- wolffd@0: % the two //competing// weights are now balanced wolffd@0: % --- wolffd@0: w = thisw - symmw; wolffd@0: wolffd@0: % --- wolffd@0: % set both edges wolffd@0: % --- wolffd@0: G.E(V1,V2) = max(w,0); wolffd@0: G.E(V2,V1) = -min(w,0); wolffd@0: wolffd@0: % if w >= 0 wolffd@0: % G.E(V1,V2) = w; wolffd@0: % G.E(V2,V1) = 0; wolffd@0: % elseif w < 0 wolffd@0: % G.E(V1,V2) = 0; wolffd@0: % G.E(V2,V1) = -w; wolffd@0: % end wolffd@0: end wolffd@0: wolffd@0: end wolffd@0: wolffd@0: methods (Hidden) wolffd@0: wolffd@0: % --- wolffd@0: % This is the core function of this Graph. wolffd@0: % it allows for the calculation of a single Edge, wolffd@0: % before it is balanced with its symmetrical counteredge wolffd@0: % wolffd@0: % --- wolffd@0: function thisw = unbal_edge_weight(G, V1, V2) wolffd@0: % --- wolffd@0: % trivial cases wolffd@0: % --- wolffd@0: if isempty(G.hE(V1, V2)) || isempty(G.hE{V1, V2}) wolffd@0: thisw = 0; wolffd@0: return; wolffd@0: end wolffd@0: wolffd@0: % --- wolffd@0: % Evaluate the single historical entries wolffd@0: % and sum up wolffd@0: % --- wolffd@0: thisw = sum(G.hE{V1, V2},1); wolffd@0: wolffd@0: % --- wolffd@0: % now divide the single votes by the number of wolffd@0: % votes totally made with the option to improve wolffd@0: % this edge wolffd@0: % --- wolffd@0: thisw = thisw(1) / thisw(2); wolffd@0: wolffd@0: end wolffd@0: end wolffd@0: end