├── examples ├── geosurf.h5 └── spinglass.uai ├── setup.m ├── ICML experiments └── Partition func & temperature │ ├── results.mat │ ├── generate_data.m │ ├── run_experiment.m │ ├── compute_answers.m │ ├── plot_comparison.m │ └── ZgibbsIsing4.m ├── inference ├── compute_log_z.m ├── tt_factors.m ├── tt_potentials.m ├── compute_marginals.m ├── compute_log_z_array.m ├── tt_log_sum_prod.m └── tt_marginals_from_factors.m ├── utils ├── save_figure.m ├── compute_log_z_array_jt.m ├── plot_quartiles.m └── process_options.m ├── models ├── get_neighborhood4.m ├── load_opengm_model.m ├── load_uai_model.m └── generate_spin_glass_model.m ├── LICENSE └── README.md /examples/geosurf.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bihaqo/TT-MRF/HEAD/examples/geosurf.h5 -------------------------------------------------------------------------------- /setup.m: -------------------------------------------------------------------------------- 1 | cd utils/ 2 | addpath(pwd) 3 | cd ../ 4 | 5 | cd models 6 | addpath(pwd) 7 | cd ../ 8 | 9 | cd inference 10 | addpath(pwd) 11 | cd ../ 12 | -------------------------------------------------------------------------------- /ICML experiments/Partition func & temperature/results.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bihaqo/TT-MRF/HEAD/ICML experiments/Partition func & temperature/results.mat -------------------------------------------------------------------------------- /inference/compute_log_z.m: -------------------------------------------------------------------------------- 1 | function [logZ, logAbsErrorBound, time] = compute_log_z(Model, roundingPrecision, varargin) 2 | % Find logarithm of the partition function Z for the graphical model using Tensor Train decomposition. 3 | % 4 | 5 | tic; 6 | factors = tt_factors(Model); 7 | if nargout == 1 8 | logZ = tt_log_sum_prod(factors, roundingPrecision, varargin{:}); 9 | else 10 | [logZ, logAbsErrorBound] = tt_log_sum_prod(factors, roundingPrecision, varargin{:}); 11 | end 12 | time = toc; 13 | end -------------------------------------------------------------------------------- /utils/save_figure.m: -------------------------------------------------------------------------------- 1 | function save_figure(figureHandler, filename) 2 | % Store figure in .fig, .png, .eps and tikz formats 3 | % 4 | 5 | set(gcf, 'PaperPositionMode', 'auto'); 6 | saveas(figureHandler, [filename, '.fig'], 'fig'); 7 | print('-depsc2', [filename, '.eps']); 8 | print('-dpng', [filename, '.png']); 9 | try 10 | matlab2tikz('figurehandle', figureHandler, 'filename', [filename, '.tikz']); 11 | catch err 12 | warning('Cannot save figure in the Tikz format, make sure that matlab2tikz library is installed.'); 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /inference/tt_factors.m: -------------------------------------------------------------------------------- 1 | function factors = tt_factors(Model) 2 | % Find TT representation of model factors. 3 | % 4 | 5 | factors = cell(Model.numFactors, 1); 6 | for iFactor = 1 : Model.numFactors 7 | vars = Model.libdaiFactors{iFactor}.Member; 8 | % TT related routines assume that variable numbers are starting from 1. 9 | vars = vars + 1; 10 | table = Model.libdaiFactors{iFactor}.P; 11 | currFactor = tt_tensor(table); 12 | 13 | % Build enlarged tensor with nonessential dimensions. 14 | factors{iFactor} = add_non_essential_dims(currFactor, Model.modeSizes, vars); 15 | end 16 | end -------------------------------------------------------------------------------- /models/get_neighborhood4.m: -------------------------------------------------------------------------------- 1 | function [i, j] = get_neighborhood4(n, m) 2 | % Return edges in 4-connected grid to feed sparse matrix: 3 | % i(1) <-> j(1) is the first horisontal edge 4 | % ... 5 | 6 | % Horisontal edges 7 | hor_i = [1:(n * (m-1))]'; 8 | hor_j = [(n+1):(n*m)]'; 9 | 10 | % Vertical edges 11 | ver_i = []; 12 | ver_j = []; 13 | for column_idx = 1:m 14 | column = get_column(n, m, column_idx); 15 | ver_i = [ver_i; column(1:end-1)]; 16 | ver_j = [ver_j; column(2:end)]; 17 | end 18 | i = [hor_i; ver_i]; 19 | j = [hor_j; ver_j]; 20 | end 21 | 22 | function column = get_column(n, m, idx) 23 | start_idx = (idx - 1) * n + 1; 24 | column = [start_idx:(start_idx + n - 1)]'; 25 | end 26 | -------------------------------------------------------------------------------- /inference/tt_potentials.m: -------------------------------------------------------------------------------- 1 | function potentials = tt_potentials(Model) 2 | % Find TT representation of model potentials (minus logarithm of factors). 3 | % 4 | 5 | potentials = cell(Model.numFactors, 1); 6 | for iFactor = 1 : Model.numFactors 7 | vars = Model.libdaiFactors{iFactor}.Member; 8 | % TT related routines assume that variable numbers are starting from 1. 9 | vars = vars + 1; 10 | factorTable = Model.libdaiFactors{iFactor}.P; 11 | factorTable(factorTable < 1e-10) = 1e-10; 12 | potentialTable = -log(factorTable); 13 | currPotential = tt_tensor(potentialTable); 14 | % Build enlarged tensor with nonessential dimensions. 15 | potentials{iFactor} = add_non_essential_dims(currPotential, Model.modeSizes, vars); 16 | end 17 | end -------------------------------------------------------------------------------- /utils/compute_log_z_array_jt.m: -------------------------------------------------------------------------------- 1 | function [logZ] = compute_log_z_array_jt(modelCellArray) 2 | % Compute logZ for a cell array of models with the Junction tree method 3 | % from the libDAI library (this method is exact). Shows progress bar. 4 | % 5 | 6 | counter = cell(size(modelCellArray)); 7 | counter(:) = num2cell((1:numel(modelCellArray)) / numel(modelCellArray)); 8 | 9 | function [logZ] = jtreeFunc(Model, counter) 10 | persistent waitbarH; 11 | if isempty(waitbarH) || ~ishandle(waitbarH) 12 | waitbarH = waitbar(0, 'Computing logZ with the Junction Tree method.'); 13 | end 14 | 15 | [logZ, ~, ~] = dai_jtree(Model.libdaiFactors, { 1 }, '[updates=HUGIN]'); 16 | 17 | waitbar(counter, waitbarH); 18 | if counter == 1 19 | % Last call. 20 | close(waitbarH); 21 | end 22 | end 23 | [logZ] = cellfun(@jtreeFunc, modelCellArray, counter); 24 | end 25 | -------------------------------------------------------------------------------- /inference/compute_marginals.m: -------------------------------------------------------------------------------- 1 | function [unaryMarginals, logZ, time] = compute_marginals(Model, roundingPrecision, varargin) 2 | % Approximate the marginal distributions and the partition function of 3 | % an MRF defined by a using the Tensor Train approach. 4 | % 5 | % Optional arguments: 6 | % o mv -- [exact] or amen. That method to use for matrix by vector multiplication. 7 | % o rmax -- [inf] maximal rank for intermediate tensors. 8 | % o verb -- [1] verbosity level, 0-silent, 1-full info. 9 | % 10 | % Output: 11 | % o unaryMarginals -- d x n matrix, marginal distribution for each variable. 12 | % o logZ -- d x 1 vector, log(Z) computed by summing unnormalized marginal distribution. 13 | % 14 | 15 | tic; 16 | factors = tt_factors(Model); 17 | [unaryMarginals, logZ] = tt_marginals_from_factors(factors, roundingPrecision, varargin{:}); 18 | time = toc; 19 | end 20 | -------------------------------------------------------------------------------- /ICML experiments/Partition func & temperature/generate_data.m: -------------------------------------------------------------------------------- 1 | function modelCellArray = generate_data(n, m, temperatureArray, J, numAverages) 2 | % Generate cell array of spin glass models with grid size equals to n x m 3 | % and all pairwise weights fixed to J. 4 | % For each temperature numAverages models with different random 5 | % unary weights are generted (each time from the uniform distribution on [-1, 1]). 6 | % 7 | % modelCellArray is a cell array of size numAverages by length(temperatureArray). 8 | % modelCellArray{i, j} has temperature equals to temperatureArray(j). 9 | % 10 | 11 | numTemerature = length(temperatureArray); 12 | modelCellArray = cell(numAverages, numTemerature); 13 | for iAverage = 1 : numAverages 14 | unaryType = 'rand'; 15 | for iTemerature = 1 : numTemerature 16 | currTemperature = temperatureArray(iTemerature); 17 | currModel = generate_spin_glass_model(n, m, currTemperature, 'J', J, 'H', unaryType); 18 | modelCellArray{iAverage, iTemerature} = currModel; 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /utils/plot_quartiles.m: -------------------------------------------------------------------------------- 1 | function p = plot_quartiles(x, y, spec, lineWidth) 2 | % Plot median and upper and lower quartiles as error bars. Returns the plot 3 | % handler. 4 | % 5 | % Input: 6 | % x -- vector 1 x N with X values 7 | % y -- matrix M x N with all Y values. 8 | % 9 | % Optional input: 10 | % spec -- character string which defines line specifications (see help plot) 11 | % lineWidth -- number 12 | % 13 | 14 | [quartiles] = quantile(y, [0.25, 0.5, 0.75]); 15 | errorDown = quartiles(2, :) - quartiles(1, :); 16 | median = quartiles(2, :); 17 | errorUp = quartiles(3, :) - quartiles(2, :); 18 | if nargin >= 3 19 | p = errorbar(x, median, errorDown, errorUp, spec); 20 | else 21 | p = errorbar(x, median, errorDown, errorUp); 22 | end 23 | 24 | hb = get(p, 'children'); 25 | if nargin >= 4 26 | set(hb(1), 'Linewidth', lineWidth); 27 | end 28 | % Error bar line width. 29 | set(hb(2), 'Linewidth', 0.5); 30 | 31 | set(hb(1),'MarkerSize', 5); 32 | set(hb(1),'MarkerFaceColor', [0 0 0]); 33 | set(hb(1),'MarkerEdgeColor', [0 0 0]); 34 | end 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alexander Novikov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /ICML experiments/Partition func & temperature/run_experiment.m: -------------------------------------------------------------------------------- 1 | % Reproduce the partition function experiment from the ICML paper. 2 | % 3 | % This script generates an Ising models dataset where temperature varies from 10^-1 to 10^3, 4 | % computes the partition function with different approaches and plot the comparison. 5 | % 6 | % You can access original dataset used in the ICML paper here: 7 | % https://www.dropbox.com/s/6onvwjz4avva72m/data.mat 8 | % 9 | 10 | ttRoundingPrecision = 1e-10; 11 | n = 10; 12 | m = 10; 13 | temperatureArray = 10.^[-1:0.1:3]; 14 | J = 1; 15 | numAverages = 50; 16 | 17 | % Fix seed for reproducibility. 18 | rng(0); 19 | 20 | modelCellArray = generate_data(n, m, temperatureArray, J, numAverages); 21 | save('data.mat', 'modelCellArray', 'n', 'm', 'temperatureArray', 'J', 'numAverages'); 22 | 23 | [logZ_TT, logAbsErrorBound_TT, time_TT, logZ_JT, ... 24 | logZ_BP, time_BP, logZ_MF, time_MF, ... 25 | logZ_TREEEP, time_TREEEP, logZ_AIS, time_AIS] = compute_answers(modelCellArray, ttRoundingPrecision); 26 | 27 | save('results.mat', 'temperatureArray', 'logZ_TT', 'logAbsErrorBound_TT', 'time_TT', 'logZ_JT', 'logZ_BP', 'time_BP', 'logZ_MF', 'time_MF', 'logZ_TREEEP', 'time_TREEEP', 'logZ_AIS', 'time_AIS'); 28 | 29 | 30 | plot_comparison(temperatureArray, logZ_TT, logZ_JT, logZ_BP, logZ_MF, logZ_TREEEP, logZ_AIS); 31 | -------------------------------------------------------------------------------- /models/load_opengm_model.m: -------------------------------------------------------------------------------- 1 | function Model = load_opengm_model(opengmFilename, dataset) 2 | 3 | if exist(opengmFilename, 'file') == 0 4 | error(['File ', opengmFilename, ' does not exist!']) 5 | end 6 | 7 | if nargin == 1 8 | warning('Dataset is unspecified, using "gm".') 9 | dataset = 'gm'; 10 | end 11 | 12 | gm = openGMModel; 13 | gm.load(opengmFilename, dataset); 14 | 15 | numNodes = gm.numberOfVariables(); 16 | modeSizes = zeros(1, numNodes); 17 | for iNode = 1:numNodes 18 | modeSizes(iNode) = gm.numberOfLabels(iNode - 1); 19 | end 20 | 21 | numFactors = gm.numberOfFactors(); 22 | libdaiFactors = cell(numFactors, 1); 23 | for iFactor = 1:numFactors 24 | % In OpenGM potentials (-logarithms of factors) called factors. 25 | % Thats why we are getting currPotentialTable with getFactorTable method. 26 | [currPotentialTable, vars] = gm.getFactorTable(iFactor - 1); 27 | assert(issorted(vars), 'Error: we assumed that each factor in OpenGM model ',... 28 | 'has sorted list of variables, but it is not the case!'); 29 | libdaiFactors{iFactor}.Member = vars; 30 | libdaiFactors{iFactor}.P = exp(-currPotentialTable); 31 | end 32 | 33 | Model.libdaiFactors = libdaiFactors; 34 | Model.numNodes = numNodes; 35 | Model.modeSizes = modeSizes; 36 | Model.numFactors = numFactors; 37 | 38 | Model.type = 'OpenGM'; 39 | Model.description = ['OpenGM model loaded from file "', opengmFilename, '" (dataset "', dataset, '")']; 40 | end -------------------------------------------------------------------------------- /inference/compute_log_z_array.m: -------------------------------------------------------------------------------- 1 | function [logZ, time, logAbsErrorBound] = compute_log_z_array(modelCellArray, roundingPrecision) 2 | % Compute logZ for a cell array of models with the Tensor Train based 3 | % method. If the Tensor Train method fails for some model, show warning, 4 | % save the model into the errors.mat file, return 0 as logZ and continue. 5 | % Shows progress bar. 6 | % 7 | 8 | counter = cell(size(modelCellArray)); 9 | counter(:) = num2cell((1:numel(modelCellArray)) / numel(modelCellArray)); 10 | 11 | function [logZ, logAbsErrorBound, time] = ttFunc(Model, counter) 12 | persistent waitbarH; 13 | if isempty(waitbarH) || ~ishandle(waitbarH) 14 | waitbarH = waitbar(0, ['Computing logZ with the Tensor Train method ', ... 15 | '(precision is ', num2str(roundingPrecision), ').']); 16 | end 17 | 18 | try 19 | [logZ, logAbsErrorBound, time] = compute_log_z(Model, roundingPrecision); 20 | catch err 21 | warning(['TT method didn''t succeed on the current model. Model ', ... 22 | 'saved to the errors.mat file.']); 23 | disp(err); 24 | logZ = 0; 25 | logAbsErrorBound = inf; 26 | time = 0; 27 | if exist('errors.mat', 'file') 28 | load('errors.mat'); 29 | badModels{end + 1} = Model; 30 | else 31 | badModels = {Model}; 32 | end 33 | save('errors.mat', 'badModels'); 34 | end 35 | 36 | disp(['Computed loZ with TT method in ', num2str(time), ' seconds.']); 37 | 38 | waitbar(counter, waitbarH); 39 | if counter == 1 40 | % Last call. 41 | close(waitbarH); 42 | end 43 | end 44 | [logZ, logAbsErrorBound, time] = cellfun(@ttFunc, modelCellArray, counter); 45 | end 46 | -------------------------------------------------------------------------------- /models/load_uai_model.m: -------------------------------------------------------------------------------- 1 | function Model = load_uai_model(uaiFilename) 2 | 3 | if exist(uaiFilename, 'file') == 0 4 | error(['File ', uaiFilename, ' does not exist!']) 5 | end 6 | 7 | 8 | fid = fopen(uaiFilename); 9 | mrfType = fscanf(fid, '%s', 1); 10 | if ~strcmp(mrfType, 'MARKOV') 11 | error(['Unsupported MRF type:', mrfType]) 12 | end 13 | numNodes = fscanf(fid, '%d', 1); 14 | modeSizes = fscanf(fid, '%d', numNodes)'; 15 | 16 | numFactors = fscanf(fid, '%d', 1); 17 | factorVars = cell(numFactors, 1); 18 | for iFactor = 1:numFactors 19 | numCurrFactorVars = fscanf(fid, '%d', 1); 20 | factorVars{iFactor} = fscanf(fid, '%d', numCurrFactorVars) + 1; 21 | end 22 | 23 | libdaiFactors = cell(numFactors, 1); 24 | for iFactor = 1:numFactors 25 | currFactorSize = fscanf(fid, '%d', 1); 26 | currFactorTable = fscanf(fid, '%f', currFactorSize); 27 | currModeSizes = modeSizes(factorVars{iFactor}); 28 | if length(currModeSizes) > 1 29 | % Memory order in uai format is different from the matlab one, so we need to rearrange dimensions. 30 | currFactorTable = reshape(currFactorTable, currModeSizes(end:-1:1)); 31 | new_order = length(currModeSizes):-1:1; 32 | currFactorTable = permute(currFactorTable, new_order); 33 | end 34 | libdaiFactors{iFactor}.Member = factorVars{iFactor}' - 1; 35 | libdaiFactors{iFactor}.P = currFactorTable; 36 | end 37 | fclose(fid); 38 | 39 | Model.libdaiFactors = libdaiFactors; 40 | Model.numNodes = numNodes; 41 | Model.modeSizes = modeSizes; 42 | Model.numFactors = numFactors; 43 | 44 | Model.type = 'UAI'; 45 | Model.description = ['UAI model loaded from file "', uaiFilename, '"']; 46 | end 47 | -------------------------------------------------------------------------------- /ICML experiments/Partition func & temperature/compute_answers.m: -------------------------------------------------------------------------------- 1 | function [logZ_TT, logAbsErrorBound_TT, time_TT, logZ_JT, ... 2 | logZ_BP, time_BP, logZ_MF, time_MF, ... 3 | logZ_TREEEP, time_TREEEP, logZ_AIS, time_AIS] = compute_answers(modelCellArray, ttRoundingPrecision) 4 | 5 | % Compute log partition function with different methods 6 | % for all models from modelCellArray. 7 | 8 | % Tensor Train. 9 | ttFunc = @(Model) compute_log_z(Model, ttRoundingPrecision); 10 | [logZ_TT, logAbsErrorBound_TT, time_TT] = cellfun(ttFunc, modelCellArray); 11 | 12 | % Junction tree (exact method). 13 | function [logZ_JT] = jtreeFunc(Model) 14 | [logZ_JT, ~, ~] = dai_jtree(Model.libdaiFactors, { 1 }, '[updates=HUGIN]'); 15 | end 16 | [logZ_JT] = cellfun(@jtreeFunc, modelCellArray); 17 | 18 | % Belief Propagation. 19 | function [logZ_BP, time_BP] = bpFunc(Model) 20 | tic; 21 | [logZ_BP, ~, ~] = dai(Model.libdaiFactors, 'BP', '[maxiter=1000,tol=1e-8,verbose=0,logdomain=1,updates=SEQMAX]'); 22 | time_BP = toc; 23 | end 24 | [logZ_BP, time_BP] = cellfun(@bpFunc, modelCellArray); 25 | 26 | % Mean Field. 27 | function [logZ_MF, time_MF] = mfFunc(Model) 28 | tic; 29 | [logZ_MF, ~, ~] = dai(Model.libdaiFactors, 'MF', '[maxiter=1000,tol=1e-8,verbose=0,updates=NAIVE]'); 30 | time_MF = toc; 31 | end 32 | [logZ_MF, time_MF] = cellfun(@mfFunc, modelCellArray); 33 | 34 | % Tree Expectation Propagation. 35 | function [logZ_TREEEP, time_TREEEP] = treeepFunc(Model) 36 | tic; 37 | [logZ_TREEEP, ~, ~] = dai(Model.libdaiFactors, 'TREEEP', '[maxiter=1000,tol=1e-8,type=ORG,verbose=0]'); 38 | time_TREEEP = toc; 39 | end 40 | [logZ_TREEEP, time_TREEEP] = cellfun(@treeepFunc, modelCellArray); 41 | 42 | % Annealing important sampling. 43 | function [logZ_AIS, time_AIS] = aisFunc(Model) 44 | if strcmp(Model.edgesType, 'number') 45 | J = Model.edgeWeights(1); 46 | tic; 47 | logZ_AIS = ZgibbsIsing4(Model.unaryWeights, J, 1/Model.temperature, 1000, 70); 48 | time_AIS = toc; 49 | else 50 | warning('AIS does not support multiple pairwise weights'); 51 | logZ_AIS = 0; 52 | time_AIS = 0; 53 | end 54 | end 55 | [logZ_AIS, time_AIS] = cellfun(@aisFunc, modelCellArray); 56 | end 57 | -------------------------------------------------------------------------------- /ICML experiments/Partition func & temperature/plot_comparison.m: -------------------------------------------------------------------------------- 1 | function plot_comparison(temperatureArray, logZ_TT, logZ_JT, logZ_BP, logZ_MF, logZ_TREEEP, logZ_AIS) 2 | logZ_true = logZ_JT; 3 | 4 | h = figure; 5 | hold all; 6 | p_arr = []; 7 | legends = {}; 8 | 9 | p_arr(end + 1) = plot_method(temperatureArray, logZ_BP - logZ_true, '-s', [0 0 0], 1); 10 | legends{end + 1} = 'BP'; 11 | 12 | p_arr(end + 1) = plot_method(temperatureArray, logZ_MF - logZ_true, '-v', [0 0 0], 1); 13 | legends{end + 1} = 'MF'; 14 | 15 | p_arr(end + 1) = plot_method(temperatureArray, logZ_TREEEP - logZ_true, 'o-', [ 0 0 0], 1); 16 | legends{end + 1} = 'TREEEP'; 17 | 18 | p_arr(end + 1) = plot_method(temperatureArray, logZ_AIS - logZ_true, '-^', [0 0 0], 1); 19 | legends{end + 1} = 'MCMC - AIS'; 20 | 21 | p_arr(end + 1) = plot_method(temperatureArray, logZ_TT - logZ_true, '-', [1 0 0], 1.5); 22 | legends{end + 1} = 'TT'; 23 | 24 | hLegend = legend(p_arr, legends); 25 | 26 | hXLabel = xlabel('temperature T'); 27 | hYLabel = ylabel('$|\log \hat{Z} - \log Z|$', 'Interpreter','latex'); 28 | set(gca,'YScale','log','YMinorTick','on',... 29 | 'YColor',[0.3 0.3 0.3],... 30 | 'XScale','log',... 31 | 'XMinorTick','on',... 32 | 'XColor',[0.3 0.3 0.3],... 33 | 'TickDir','out',... 34 | 'TickLength',[0.02 0.02],... 35 | 'Position',[0.095360824742268 0.138888888888889 0.868556701030928 0.845238095238095],... 36 | 'FontName','Times New Roman'); 37 | save_figure(h, 'Error comparison'); 38 | end 39 | 40 | 41 | function p = plot_method(x_vals, results, spec, color, width) 42 | y = abs(results); 43 | 44 | [quartiles] = quantile(y, [0.25, 0.5, 0.75]); 45 | error_down = quartiles(2, :) - quartiles(1, :); 46 | mean_values = quartiles(2, :); 47 | error_up = quartiles(3, :) - quartiles(2, :); 48 | p = errorbar(x_vals, mean_values, error_down, error_up, spec); 49 | 50 | % Line color. 51 | set(p, 'Color', color); 52 | 53 | hb = get(p, 'children'); 54 | % Line width. 55 | set(hb(1), 'Linewidth', width); 56 | % Error bar line width. 57 | set(hb(2), 'Linewidth', 0.5); 58 | 59 | set(hb(1),'MarkerSize', 5); 60 | set(hb(1),'MarkerFaceColor', [0 0 0]); 61 | set(hb(1),'MarkerEdgeColor', [0 0 0]); 62 | end 63 | -------------------------------------------------------------------------------- /ICML experiments/Partition func & temperature/ZgibbsIsing4.m: -------------------------------------------------------------------------------- 1 | function logZ = ZgibbsIsing4(H, J, beta, num_pdfs, num_iter) 2 | % Estimate the partition function with Gibbs sampling. 3 | % 4 | % logZ = ZgibbsIsing4(H, J, beta, num_pdfs, num_iter) 5 | % 6 | % Input 7 | % H -- N x M matrix, external magnetic field 8 | % J -- number, global pairwise wight; 9 | % beta -- 1 x num_temp vector, 1/(kT) values; 10 | % num_pdfs -- integer, number of intermediate distributions; 11 | % num_iter -- integer, number of iterations; 12 | % 13 | % Output 14 | % logZ -- 1 x num_temp vector, logarithms of the partition function for all provided beta values; 15 | % 16 | % 17 | % Author: Dmitry Kropotov (kropotov -at- bayesgroup.ru) 18 | % 19 | 20 | if nargin ~= 5 21 | error('Wrong number of input arguments.'); 22 | end 23 | 24 | if ~isnumeric(H) || (length(size(H))>2) 25 | error('External magnetic field parameter H should be a matrix.'); 26 | end 27 | 28 | if ~isnumeric(J) || (length(size(J))>2) || (norm(size(J) - [1 1])~=0) 29 | error('Pairwise weight J should be a number.'); 30 | end 31 | 32 | if ~isnumeric(beta) || (length(size(beta))>2) || (size(beta,1)>1) || any(beta<=0) 33 | error('Beta parameter should be a vector of real values.'); 34 | end 35 | 36 | if ~isnumeric(num_pdfs) || (length(size(num_pdfs))>2) || (norm(size(num_pdfs)-[1 1])~=0) || (fix(num_pdfs)~=num_pdfs) || (num_pdfs < 1) 37 | error('Number of intermediate distributions is not a natural number.'); 38 | end 39 | 40 | if ~isnumeric(num_iter) || (length(size(num_iter))>2) || (norm(size(num_iter)-[1 1])~=0) || (fix(num_iter)~=num_iter) || (num_iter<1) 41 | error('Number of iterations is not a natural number.'); 42 | end 43 | 44 | 45 | rng('Shuffle'); 46 | 47 | t_start = tic; 48 | 49 | [N,M] = size(H); 50 | NM = N*M; 51 | num_beta = length(beta); 52 | 53 | % 1 - outside element 54 | index = reshape(2 : (NM + 1), [N, M]); 55 | 56 | numN = 4; 57 | neighbors = ones(N, M, numN); 58 | neighbors(1 : end - 1, :, 1) = index(2 : end, :); 59 | neighbors(2 : end, :, 2) = index(1 : end - 1, :); 60 | neighbors(:, 1 : end - 1, 3) = index(:, 2 : end); 61 | neighbors(:, 2 : end, 4) = index(:, 1 : end - 1); 62 | 63 | nN = ones(NM + 1, numN); 64 | for c = 1 : numN 65 | nN(2 : end, c) = reshape(neighbors(:, :, c), [NM, 1]); 66 | end 67 | 68 | hN = [0; H(:)]; 69 | 70 | alpha = 0:1/(num_pdfs-1):1; 71 | 72 | w = zeros(num_iter, num_beta); 73 | fprintf('Total %d iterations:', num_iter); 74 | for iter = 1:num_iter 75 | 76 | if mod(iter, 30) == 0 77 | fprintf('\n'); 78 | end 79 | fprintf(' %d', iter); 80 | 81 | % Generate points from uniform distrition. 82 | currX = round(rand(NM + 1, num_beta)) * 2 - 1; 83 | currX(1, :) = 0; 84 | 85 | energy = zeros(num_pdfs-1, num_beta); 86 | 87 | % Compute energies of generated configurations. 88 | for c = 1:numN 89 | energy(1,:) = energy(1,:) - sum(currX .* currX(nN(:,c),:), 1); 90 | end 91 | energy(1,:) = J*energy(1,:)/2 - sum(currX .* repmat(hN, [1, num_beta]), 1); 92 | 93 | for i_alpha = 2:length(alpha)-1 94 | 95 | % Do one step of Gibbs sampling for p_alpha distribution. 96 | for i = 2 : NM + 1 97 | p1 = 1 ./ (1 + exp(-2 * alpha(i_alpha)*beta .*(J * sum(currX(nN(i, :), :), 1) + hN(i)))); 98 | currX(i, :) = 1 - 2 * (rand(1, num_beta) > p1); 99 | end 100 | % Compute energy of current configuration. 101 | for c = 1 : numN 102 | energy(i_alpha, :) = energy(i_alpha, :) - sum(currX .* currX(nN(:, c), :), 1); 103 | end 104 | energy(i_alpha, :) = energy(i_alpha, :) * J / 2 - sum(currX .* repmat(hN, [1, num_beta]), 1); 105 | end 106 | w(iter,:) = -beta.*sum(energy, 1)/(num_pdfs-1); 107 | end 108 | fprintf('\n'); 109 | 110 | wmax = max(w, [], 1); 111 | logZ = log(sum(exp(bsxfun(@minus, w, wmax)),1)) + wmax - log(num_iter) + NM*log(2); 112 | 113 | t_finish = toc(t_start); 114 | fprintf('Total time = %.4f\n', t_finish); 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TT-MRF 2 | ====== 3 | 4 | TT-MRF is a library for Markov random field inference with Tensor Train decomposition approach. The code is published in support to the following paper: 5 | 6 | Putting MRFs on a Tensor Train 7 | Alexander Novikov, Anton Rodomanov, Anton Osokin, Dmitry Vetrov; In _Proceedings of The 31st International Conference on Machine Learning_ (ICML-2014) [[paper](https://www.dropbox.com/s/d479j6zocine232/Paper.pdf)] [[suppl.](https://www.dropbox.com/s/ozbnccf0rxlzu9m/Supplementary.pdf)] [[poster](https://www.dropbox.com/s/49ed3vqrvtxbq0v/Poster.pdf)]. 8 | 9 | Please cite it if you write scientific paper using this code. 10 | In BiBTeX format: 11 | ```latex 12 | @article{novikov14tt, 13 | author = {Novikov, Alexander and Rodomanov, Anton and Osokin, Anton and Vetrov, Dmitry}, 14 | title = {Putting {MRF}s on a {T}ensor {T}rain}, 15 | journal = {Proceedings of The 31st International Conference on Machine Learning}, 16 | year = {2014}, 17 | } 18 | ``` 19 | 20 | Install 21 | ======= 22 | 23 | Install the [TT-Toolbox](https://github.com/oseledets/TT-Toolbox) (just download it and run `setup.m` to add everything important to MATLAB path). 24 | 25 | Run `setup.m` to add required folders to MATLAB path. 26 | 27 | Optional dependencies 28 | --------------------- 29 | 30 | If you want to compare with state-of-the-art techniques for computing partition function and marginal distributions, install [LibDAI](http://staff.science.uva.nl/~jmooij1/libDAI/) library with the MATLAB support. 31 | 32 | If you need access to state-of-the-art MAP-inference routines OR want to be able to load models in OpenGM format, install [OpenGM](hci.iwr.uni-heidelberg.de/opengm2/) with MATLAB, HDF5, TRW-S and Maxflow support. Example bash input for compiling OpenGM: 33 | ``` bash 34 | cd opengm_folder 35 | cmake . -DWITH_MATLAB=ON -DWITH_HDF5=ON -DBUILD_MATLAB_WRAPPER=ON -DWITH_TRWS=ON -DWITH_MAXFLOW=ON 36 | make 37 | ``` 38 | 39 | 40 | Model format 41 | ============== 42 | 43 | We use custom graphical model instance format. You can build problems like this: 44 | ``` MATLAB 45 | % Build 5x4 grid spin glass model with temperature = 2. 46 | Model = generate_spin_glass_model(5, 4, 2); 47 | 48 | % Load model in OpenGM format. 49 | Model = load_opengm_model('examples/geosurf.h5'); 50 | 51 | % Load model in uai format. 52 | Model = load_uai_model('examples/spinglass.uai'); 53 | ``` 54 | 55 | Format details: 56 | ``` MATLAB 57 | Model.libdaiFactors [Cell array] factors of the model in the LibDAI format 58 | Model.numNodes [Number] number of Model variables 59 | Model.modeSizes [Vector 1 x d] sizes of variables (e.g. x_1 is from {1, ..., modeSizes(1)}) 60 | Model.description [String] text description 61 | Model.type [String] Type: 'Spin glass', 'OpenGM' or 'UAI' 62 | 63 | % Problem specific, spin glass 64 | Model.grid_n [Number] vertical size of spin glass model grid 65 | Model.grid_m [Number] horizontal size of spin glass model grid 66 | Model.temperature [Number] 67 | Model.unaryWeights [Matrix n x m] 68 | Model.unaryType [String] 'number' if all unary weights equals to one number; 69 | 'matrix' matrix with unary weights was specified during model generation; 70 | 'rand' if weights were generated from uniform distribution 71 | Model.unaryDistr [Vector 1 x 2] unary wights uniform distribution support 72 | (e.g. [-1, 1] means that weights are from U(-1, 1)) 73 | Model.edgeWeights [Vector numEdges x 1] all pairwise weights 74 | Model.edgeType [String] 'number' or 'rand', see details in unryType description 75 | Model.edgesDistr [Vector 1 x 2] pairwise weight uniform distribution support 76 | ``` 77 | 78 | 79 | Example code 80 | ============== 81 | ``` MATLAB 82 | % Build 5x4 grid spin glass model with temperature = 2 83 | % and pairwise weights generated from uniform distribution on [0, 1]. 84 | Model = generate_spin_glass_model(5, 4, 2, 'J', 'rand', 'J_distr', [0, 1]); 85 | 86 | % Compute logarithm of the partition function using Tensor Train approach 87 | % with rounding precision equals 1e-6. 88 | logZ = compute_log_z(Model, 1e-6); 89 | 90 | % Compute logarithm of the partition function using junction tree method from the libDAI library. 91 | [logZ_JT, ~, ~] = dai_jtree(Model.libdaiFactors, { 1 }, '[updates=HUGIN]'); 92 | 93 | relError = (logZ_JT - logZ) / logZ_JT; 94 | disp(['Computed logarithm of the partition function with relative error ', num2str(relError)]) 95 | ``` 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /utils/process_options.m: -------------------------------------------------------------------------------- 1 | % PROCESS_OPTIONS - Processes options passed to a Matlab function. 2 | % This function provides a simple means of 3 | % parsing attribute-value options. Each option is 4 | % named by a unique string and is given a default 5 | % value. 6 | % 7 | % Usage: [var1, var2, ..., varn[, unused]] = ... 8 | % process_options(args, ... 9 | % str1, def1, str2, def2, ..., strn, defn) 10 | % 11 | % Arguments: 12 | % args - a cell array of input arguments, such 13 | % as that provided by VARARGIN. Its contents 14 | % should alternate between strings and 15 | % values. 16 | % str1, ..., strn - Strings that are associated with a 17 | % particular variable 18 | % def1, ..., defn - Default values returned if no option 19 | % is supplied 20 | % 21 | % Returns: 22 | % var1, ..., varn - values to be assigned to variables 23 | % unused - an optional cell array of those 24 | % string-value pairs that were unused; 25 | % if this is not supplied, then a 26 | % warning will be issued for each 27 | % option in args that lacked a match. 28 | % 29 | % Examples: 30 | % 31 | % Suppose we wish to define a Matlab function 'func' that has 32 | % required parameters x and y, and optional arguments 'u' and 'v'. 33 | % With the definition 34 | % 35 | % function y = func(x, y, varargin) 36 | % 37 | % [u, v] = process_options(varargin, 'u', 0, 'v', 1); 38 | % 39 | % calling func(0, 1, 'v', 2) will assign 0 to x, 1 to y, 0 to u, and 2 40 | % to v. The parameter names are insensitive to case; calling 41 | % func(0, 1, 'V', 2) has the same effect. The function call 42 | % 43 | % func(0, 1, 'u', 5, 'z', 2); 44 | % 45 | % will result in u having the value 5 and v having value 1, but 46 | % will issue a warning that the 'z' option has not been used. On 47 | % the other hand, if func is defined as 48 | % 49 | % function y = func(x, y, varargin) 50 | % 51 | % [u, v, unused_args] = process_options(varargin, 'u', 0, 'v', 1); 52 | % 53 | % then the call func(0, 1, 'u', 5, 'z', 2) will yield no warning, 54 | % and unused_args will have the value {'z', 2}. This behaviour is 55 | % useful for functions with options that invoke other functions 56 | % with options; all options can be passed to the outer function and 57 | % its unprocessed arguments can be passed to the inner function. 58 | 59 | % Copyright (C) 2002 Mark A. Paskin 60 | % 61 | % This program is free software; you can redistribute it and/or modify 62 | % it under the terms of the GNU General Public License as published by 63 | % the Free Software Foundation; either version 2 of the License, or 64 | % (at your option) any later version. 65 | % 66 | % This program is distributed in the hope that it will be useful, but 67 | % WITHOUT ANY WARRANTY; without even the implied warranty of 68 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 69 | % General Public License for more details. 70 | % 71 | % You should have received a copy of the GNU General Public License 72 | % along with this program; if not, write to the Free Software 73 | % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 74 | % USA. 75 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76 | 77 | function [varargout] = process_options(args, varargin) 78 | 79 | % Check the number of input arguments 80 | n = length(varargin); 81 | if (mod(n, 2)) 82 | error('Each option must be a string/value pair.'); 83 | end 84 | 85 | % Check the number of supplied output arguments 86 | if (nargout < (n / 2)) 87 | error('Insufficient number of output arguments given'); 88 | elseif (nargout == (n / 2)) 89 | warn = 1; 90 | nout = n / 2; 91 | else 92 | warn = 0; 93 | nout = n / 2 + 1; 94 | end 95 | 96 | % Set outputs to be defaults 97 | varargout = cell(1, nout); 98 | for i=2:2:n 99 | varargout{i/2} = varargin{i}; 100 | end 101 | 102 | % Now process all arguments 103 | nunused = 0; 104 | for i=1:2:length(args) 105 | found = 0; 106 | for j=1:2:n 107 | if strcmpi(args{i}, varargin{j}) 108 | varargout{(j + 1)/2} = args{i + 1}; 109 | found = 1; 110 | break; 111 | end 112 | end 113 | if (~found) 114 | if (warn) 115 | warning(sprintf('Option ''%s'' not used.', args{i})); 116 | args{i} 117 | else 118 | nunused = nunused + 1; 119 | unused{2 * nunused - 1} = args{i}; 120 | unused{2 * nunused} = args{i + 1}; 121 | end 122 | end 123 | end 124 | 125 | % Assign the unused arguments 126 | if (~warn) 127 | if (nunused) 128 | varargout{nout} = unused; 129 | else 130 | varargout{nout} = cell(0); 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /models/generate_spin_glass_model.m: -------------------------------------------------------------------------------- 1 | function Model = generate_spin_glass_model(n, m, temperature, varargin) 2 | % Build problem instance for spin glass model. 3 | % 4 | % Input: 5 | % n, m -- positive integers, size of the grid 6 | % temperature -- number, temperature of the model 7 | % J -- [1] pairwise weights, can be number (all weights equal this number) 8 | % can be 'rand' (all weights are generated from uniform distribution) 9 | % J_distr -- [-1, 1] vector with two numbers, support of the J uniform distribution. 10 | % H -- [0] unary weights, can be number (all weights equal this number) 11 | % can be 'rand' (all weights are generated from uniform distribution) 12 | % can be matrix of size n by m with desired weights. 13 | % 14 | 15 | [edgesType, edgesDistr, unaryType, unaryDistr] = process_options(varargin, 'J', 1, 'J_distr', [-1, 1],... 16 | 'H', 0, 'H_distr', [-1, 1]); 17 | 18 | 19 | if strcmp(unaryType, 'rand') 20 | unaryWeights = unifrnd(unaryDistr(1), unaryDistr(2), n, m); 21 | unaryTextType = 'rand'; 22 | elseif isscalar(unaryType) 23 | unaryWeights = unaryType * ones(n, m); 24 | unaryTextType = 'number'; 25 | elseif ismatrix(unaryType) 26 | if size(unaryType) == [n, m] 27 | unaryWeights = unaryType; 28 | unaryTextType = 'matrix'; 29 | else 30 | error('H has inappropriate dimensions.') 31 | end 32 | else 33 | error('Unknown H type.'); 34 | end 35 | 36 | [edgesFrom, edgesTo] = get_neighborhood4(n, m); 37 | numEdges = length(edgesFrom); 38 | if isscalar(edgesType) 39 | edgeWeights = edgesType * ones(numEdges, 1); 40 | edgesTextType = 'number'; 41 | elseif strcmp(edgesType, 'rand') 42 | edgeWeights = unifrnd(edgesDistr(1), edgesDistr(2), numEdges, 1); 43 | edgesTextType = 'rand'; 44 | else 45 | error('Unknown J type.'); 46 | end 47 | 48 | numNodes = n * m; 49 | % There are unary and pairwise factors. 50 | numFactors = numNodes + numEdges; 51 | libdaiFactors = cell(numFactors, 1); 52 | 53 | unaryConfigurationMatrix = [-1; 1]; 54 | iFactor = 1; 55 | for iNode = 1 : numNodes 56 | if abs(unaryWeights(iNode)) > 1e-20 57 | libdaiFactors{iFactor}.Member = iNode - 1; 58 | libdaiFactors{iFactor}.P = -unaryConfigurationMatrix * unaryWeights(iNode); 59 | iFactor = iFactor + 1; 60 | end 61 | end 62 | 63 | pairwiseConfigurationMatrix = [ 1 -1; 64 | -1 1]; 65 | for iEdge = 1 : numEdges 66 | if abs(edgeWeights(iEdge)) > 1e-20 67 | libdaiFactors{iFactor}.Member = [edgesFrom(iEdge) - 1, edgesTo(iEdge) - 1]; 68 | libdaiFactors{iFactor}.P = -pairwiseConfigurationMatrix * edgeWeights(iEdge); 69 | if (edgesFrom(iEdge) > edgesTo(iEdge)) 70 | % LibDAI format assumes that nodes in Member field are in sorted order. 71 | libdaiFactors{iFactor}.Member = sort(libdaiFactors{iFactor}.Member); 72 | libdaiFactors{iFactor}.P = libdaiFactors{iFactor}.P'; 73 | end 74 | iFactor = iFactor + 1; 75 | end 76 | end 77 | % There can be less than numFactors factors, since some weights are zero. 78 | % Remove unused factors. 79 | libdaiFactors(iFactor : end) = []; 80 | numFactors = iFactor - 1; 81 | 82 | % Convert potentials to factors. 83 | for iFactor = 1 : numFactors 84 | libdaiFactors{iFactor}.P = exp( -libdaiFactors{iFactor}.P / temperature); 85 | end 86 | 87 | Model.libdaiFactors = libdaiFactors; 88 | Model.numNodes = numNodes; 89 | Model.modeSizes = 2 * ones(1, numNodes); 90 | Model.numFactors = numFactors; 91 | 92 | Model.type = 'Spin glass'; 93 | Model.grid_n = n; 94 | Model.grid_m = m; 95 | Model.temperature = temperature; 96 | Model.unaryWeights = unaryWeights; 97 | Model.unaryType = unaryTextType; 98 | if strcmp(unaryType, 'rand') 99 | Model.unaryDistr = unaryDistr; 100 | end 101 | Model.edgeWeights = edgeWeights; 102 | Model.edgesType = edgesTextType; 103 | if strcmp(edgesType, 'rand') 104 | Model.edgesDistr = edgesDistr; 105 | end 106 | 107 | Model.description = [int2str(n), 'x', int2str(m), ' spin glass grid, temp = ',... 108 | num2str(temperature), ', J ']; 109 | if isscalar(edgesType) 110 | Model.description = [Model.description, '= ', num2str(edgesType)]; 111 | elseif strcmp(edgesType, 'rand') 112 | Model.description = [Model.description, 'is uniform on [', num2str(edgesDistr(1)), ', ', num2str(edgesDistr(2)), ']']; 113 | end 114 | 115 | Model.description = [Model.description, ', H ']; 116 | if strcmp(unaryType, 'rand') 117 | Model.description = [Model.description, 'is uniform on [', num2str(unaryDistr(1)), ', ', num2str(unaryDistr(2)), '].']; 118 | elseif isscalar(unaryType) 119 | Model.description = [Model.description, '= ', num2str(unaryType), '.']; 120 | elseif ismatrix(unaryType) 121 | Model.description = [Model.description, 'is provided by user.']; 122 | end 123 | end 124 | -------------------------------------------------------------------------------- /inference/tt_log_sum_prod.m: -------------------------------------------------------------------------------- 1 | function [logSum, logAbsDiffBound] = tt_log_sum_prod(factorArray, roundingPrecision, varargin) 2 | % Find approximate log sum of elementwise product of tensors: 3 | % tt_log_sum_prod(factorArray, roundingPrecision) is an approximation to: 4 | % log(sum(factorArray{1} .* factorArray{2} .* ... .* factorArray{end})) 5 | % 6 | % Optional arguments: 7 | % o order -- ['right_to_left'] in that order we would multiply vectors and matrices. 8 | % Could be 'left_to_right' or 'right_to_left'. 9 | % o rmax -- [inf] maximal rank for intermediate tensors. 10 | % o mv -- ['exact'] or 'amen'. Matrix by vector multiplication method. 11 | % 'exact' -- multiply exactly and then apply tt_rounding 12 | % 'amen' -- use amen_mv method 13 | % o verb -- [1] verbosity level, 0-silent, 1-full info. 14 | % 15 | 16 | % Default values 17 | multiplicationOrder = 'right_to_left'; 18 | rmax = inf; 19 | isAmenMatrixByVector = false; 20 | verboseLevel = 1; 21 | 22 | isMvSpecified = false; 23 | 24 | 25 | % Read parameters from input sequence 26 | for i=1:2:length(varargin)-1 27 | switch lower(varargin{i}) 28 | case 'order' 29 | multiplicationOrder = varargin{i+1}; 30 | case 'rmax' 31 | rmax = varargin{i+1}; 32 | case 'mv' 33 | method = varargin{i+1}; 34 | if strcmp(method, 'exact') 35 | isAmenMatrixByVector = false; 36 | elseif strcmp(method, 'amen') 37 | isAmenMatrixByVector = true; 38 | else 39 | error('Unsupported matrix-by-vector multiplication method.'); 40 | end 41 | 42 | isMvSpecified = true; 43 | case 'verb' 44 | verboseLevel = varargin{i+1}; 45 | 46 | otherwise 47 | warning('Unrecognized option: %s\n',varargin{i}); 48 | end 49 | end 50 | 51 | if isAmenMatrixByVector && rmax ~= inf 52 | error('You cannot specify rmax with amen matrix-by-vector multiplication method.') 53 | end 54 | 55 | if nargout >= 2 && isAmenMatrixByVector 56 | error('Bounds on absolute error of the answer is not supported with amen matrix-by-vector multiplication method.'); 57 | end 58 | 59 | 60 | numVariables = factorArray{1}.d; 61 | numFactors = length(factorArray); 62 | 63 | factorRankArray = zeros(numVariables + 1, numFactors); 64 | factorModeSizeArray = zeros(numVariables, 1); 65 | factorCoreArray = cell(numVariables, numFactors); 66 | for iFactor = 1 : numFactors 67 | for iVariable = 1 : numVariables 68 | currCore = factorArray{iFactor}{iVariable}; 69 | [r1, n1, r2] = size(currCore); 70 | factorRankArray(iVariable, iFactor) = r1; 71 | factorModeSizeArray(iVariable) = n1; 72 | factorCoreArray{iVariable, iFactor} = currCore; 73 | end 74 | end 75 | factorRankArray(numVariables+1, :) = 1; 76 | 77 | logNormEstimateArray = zeros(numVariables, 1); 78 | matrixArray = cell(numVariables, 1); 79 | for iVariable = 1:numVariables 80 | currMatrix = []; 81 | currModeSize = factorModeSizeArray(iVariable); 82 | rowRankArray = factorRankArray(iVariable, :); 83 | colRankArray = factorRankArray(iVariable + 1, :); 84 | tp1 = tt_zeros(rowRankArray .* colRankArray); 85 | tp1 = tt_matrix(tp1, rowRankArray(:), colRankArray(:)); 86 | currNormEstimate = 0; 87 | for variableValue = 1 : currModeSize 88 | tp1LogNormEstimate = 0; 89 | for iFactor = 1 : numFactors 90 | currCore = factorCoreArray{iVariable, iFactor}; 91 | [r1, ~, r2] = size(currCore); 92 | cr1 = reshape(currCore(:, variableValue, :), [1, r1, r2, 1]); 93 | tp1{iFactor} = cr1; 94 | 95 | tp1LogNormEstimate = tp1LogNormEstimate + log(norm(reshape(cr1, r1, r2))); 96 | end 97 | currMatrix = currMatrix + tp1; 98 | currNormEstimate = currNormEstimate + exp(tp1LogNormEstimate); 99 | end 100 | matrixArray{iVariable} = currMatrix; 101 | logNormEstimateArray(iVariable) = log(currNormEstimate); 102 | end 103 | 104 | if verboseLevel >= 1 105 | sufficientPrecision = exp(log(roundingPrecision) - sum(logNormEstimateArray) - log(numVariables - 1)); 106 | disp(['To guarantee ', num2str(roundingPrecision), ' abs error use ', num2str(sufficientPrecision), ' rounding precision.']); 107 | end 108 | 109 | 110 | logAbsDiffBound = 0; 111 | fLogNormArray = zeros(numVariables, 1); 112 | if (strcmp(multiplicationOrder, 'left_to_right')) 113 | absDiffBound = 0; 114 | if isAmenMatrixByVector 115 | f = matrixArray{1}.tt; 116 | else 117 | f = matrixArray{1}; 118 | end 119 | for iVariable = 2 : numVariables 120 | fNorm = norm(f); 121 | f = f / fNorm; 122 | fLogNormArray(iVariable) = log(fNorm); 123 | if isAmenMatrixByVector 124 | f = amen_mv(transpose(matrixArray{iVariable}), f, roundingPrecision, 'verb', verboseLevel); 125 | else 126 | f = f * matrixArray{iVariable}; 127 | fRounded = round(f, roundingPrecision, rmax); 128 | absDiffBound = absDiffBound + exp(log(norm(f - fRounded)) + sum(logNormEstimateArray(iVariable+1 : end)) - sum(fLogNormArray(1 : iVariable-1))); 129 | f = fRounded; 130 | end 131 | if verboseLevel >= 1 132 | fprintf('i = %d, erank = %3.1f, max_rank = %d \n', iVariable, erank(f), max(rank(f))); 133 | end 134 | end 135 | logAbsDiffBound = log(absDiffBound); 136 | elseif (strcmp(multiplicationOrder, 'right_to_left')) 137 | absDiffBound = 0; 138 | if isAmenMatrixByVector 139 | f = matrixArray{numVariables}.tt; 140 | else 141 | f = matrixArray{numVariables}; 142 | end 143 | for iVariable = (numVariables-1):-1:1 144 | fNorm = norm(f); 145 | f = f / fNorm; 146 | fLogNormArray(iVariable) = log(fNorm); 147 | if isAmenMatrixByVector 148 | f = amen_mv(matrixArray{iVariable}, f, roundingPrecision, 'verb', verboseLevel); 149 | else 150 | f = matrixArray{iVariable} * f; 151 | fRounded = round(f, roundingPrecision, rmax); 152 | absDiffBound = absDiffBound + exp(log(norm(f - fRounded)) + sum(logNormEstimateArray(1 : iVariable-1)) - sum(fLogNormArray(iVariable+1 : end))); 153 | f = fRounded; 154 | end 155 | if verboseLevel >= 1 156 | fprintf('i = %d, erank = %3.1f, max_rank = %d \n', iVariable, erank(f), max(rank(f))); 157 | end 158 | end 159 | logAbsDiffBound = log(absDiffBound); 160 | else 161 | error('Unsupported multiplication order.') 162 | end 163 | 164 | logSum = sum(fLogNormArray) + log(full(f)); 165 | end 166 | -------------------------------------------------------------------------------- /inference/tt_marginals_from_factors.m: -------------------------------------------------------------------------------- 1 | function [unaryMarginals, logZ] = tt_marginals_from_factors(factorArray, roundingPrecision, varargin) 2 | % Approximate the marginal distributions and the partition function of 3 | % an MRF defined by a product of factors from the factorArray. 4 | % The factors should be given in the TT-format. 5 | % 6 | % Optional arguments: 7 | % o mv -- [exact] or amen. That method to use for matrix by vector multiplication. 8 | % o rmax -- [inf] maximal rank for intermediate tensors. 9 | % o verb -- [1] verbosity level, 0-silent, 1-full info. 10 | % 11 | % Output: 12 | % o unaryMarginals -- d x n matrix, marginal distribution for each variable. 13 | % o logZ -- d x 1 vector, log(Z) computed by summing unnormalized marginal distribution. 14 | % 15 | 16 | % Default values 17 | isAmenMatrixByVector = false; 18 | rmax = inf; 19 | verboseLevel = 1; 20 | 21 | % Read parameters from input sequence 22 | for i=1:2:length(varargin)-1 23 | switch lower(varargin{i}) 24 | case 'rmax' 25 | rmax = varargin{i+1}; 26 | case 'mv' 27 | method = varargin{i+1}; 28 | if strcmp(method, 'exact') 29 | isAmenMatrixByVector = false; 30 | elseif strcmp(method, 'amen') 31 | isAmenMatrixByVector = true; 32 | else 33 | error('Unsupported matrix-by-vector multiplication method.'); 34 | end 35 | case 'verb' 36 | verboseLevel = varargin{i+1}; 37 | 38 | otherwise 39 | warning('Unrecognized option: %s\n',varargin{i}); 40 | end 41 | end 42 | 43 | if isAmenMatrixByVector && rmax ~= inf 44 | error('You cannot specify rmax with amen matrix-by-vector multiplication method.') 45 | end 46 | 47 | numVariables = factorArray{1}.d; 48 | numFactors = length(factorArray); 49 | 50 | factorRankArray = zeros(numVariables + 1, numFactors); 51 | factorModeSizeArray = zeros(numVariables, 1); 52 | factorCoreArray = cell(numVariables, numFactors); 53 | for iFactor = 1 : numFactors 54 | for iVariable = 1 : numVariables 55 | currCore = factorArray{iFactor}{iVariable}; 56 | [r1, n1, r2] = size(currCore); 57 | factorRankArray(iVariable, iFactor) = r1; 58 | factorModeSizeArray(iVariable) = n1; 59 | factorCoreArray{iVariable, iFactor} = currCore; 60 | end 61 | end 62 | factorRankArray(numVariables+1, :) = 1; 63 | 64 | if any(factorModeSizeArray ~= factorModeSizeArray(1)) 65 | error('MRFs with different mode sizes are unsupported.'); 66 | end 67 | 68 | 69 | matrixArray = cell(numVariables, 1); 70 | for iVariable = 1:numVariables 71 | currMatrix = []; 72 | currModeSize = factorModeSizeArray(iVariable); 73 | rowRankArray = factorRankArray(iVariable, :); 74 | colRankArray = factorRankArray(iVariable + 1, :); 75 | tp1 = tt_zeros(rowRankArray .* colRankArray); 76 | tp1 = tt_matrix(tp1, rowRankArray(:), colRankArray(:)); 77 | for variableValue = 1 : currModeSize 78 | for iFactor = 1 : numFactors 79 | currCore = factorCoreArray{iVariable, iFactor}; 80 | [r1, ~, r2] = size(currCore); 81 | cr1 = reshape(currCore(:, variableValue, :), [1, r1, r2, 1]); 82 | tp1{iFactor} = cr1; 83 | end 84 | currMatrix = currMatrix + tp1; 85 | end 86 | matrixArray{iVariable} = currMatrix; 87 | end 88 | 89 | isTransposeLeftPref = false; 90 | 91 | leftPrefixArray = cell(numVariables, 1); 92 | leftPrefixLogNorm = zeros(numVariables, 1); 93 | if isAmenMatrixByVector 94 | f = matrixArray{1}.tt; 95 | else 96 | if isTransposeLeftPref 97 | f = matrixArray{1}'; 98 | else 99 | f = matrixArray{1}; 100 | end 101 | end 102 | if isTransposeLeftPref 103 | leftPrefixArray{1} = f'; 104 | else 105 | leftPrefixArray{1} = f; 106 | end 107 | for iVariable = 2 : numVariables 108 | if isAmenMatrixByVector 109 | f = amen_mv(transpose(matrixArray{iVariable}), f, roundingPrecision, 'verb', verboseLevel); 110 | else 111 | if isTransposeLeftPref 112 | f = matrixArray{iVariable}' * f; 113 | else 114 | f = f * matrixArray{iVariable}; 115 | end 116 | f = round(f, roundingPrecision, rmax); 117 | end 118 | currNorm = norm(f); 119 | leftPrefixLogNorm(iVariable) = leftPrefixLogNorm(iVariable - 1) + log(currNorm); 120 | f = f / currNorm; 121 | if isTransposeLeftPref 122 | leftPrefixArray{iVariable} = f'; 123 | else 124 | leftPrefixArray{iVariable} = f; 125 | end 126 | if verboseLevel >= 1 127 | fprintf('i = %d, erank = %3.1f, max_rank = %d \n', iVariable, erank(f), max(rank(f))); 128 | end 129 | end 130 | 131 | rightPostfixArray = cell(numVariables, 1); 132 | rightPostfixLogNorm = zeros(numVariables, 1); 133 | if isAmenMatrixByVector 134 | f = matrixArray{numVariables}.tt; 135 | else 136 | f = matrixArray{numVariables}; 137 | end 138 | rightPostfixArray{numVariables} = f; 139 | for iVariable = (numVariables - 1) : -1 : 1 140 | if isAmenMatrixByVector 141 | f = amen_mv(matrixArray{iVariable}, f, roundingPrecision, 'verb', verboseLevel); 142 | else 143 | f = matrixArray{iVariable} * f; 144 | f = round(f, roundingPrecision, rmax); 145 | end 146 | currNorm = norm(f); 147 | rightPostfixLogNorm(iVariable) = rightPostfixLogNorm(iVariable + 1) + log(currNorm); 148 | f = f / currNorm; 149 | rightPostfixArray{iVariable} = f; 150 | if verboseLevel >= 1 151 | fprintf('i = %d, erank = %3.1f, max_rank = %d \n', iVariable, erank(f), max(rank(f))); 152 | end 153 | end 154 | 155 | numValues = factorModeSizeArray(iVariable); 156 | unaryMarginals = zeros(numVariables, numValues); 157 | logZ = zeros(numVariables, 1); 158 | for iVariable = 1 : numVariables 159 | rowRankArray = factorRankArray(iVariable, :); 160 | colRankArray = factorRankArray(iVariable + 1, :); 161 | tp1 = tt_zeros(rowRankArray .* colRankArray); 162 | tp1 = tt_matrix(tp1, rowRankArray(:), colRankArray(:)); 163 | if iVariable > 1 164 | currLeft = leftPrefixArray{iVariable - 1}; 165 | currLeftLogNorm = leftPrefixLogNorm(iVariable - 1); 166 | else 167 | currLeft = 1; 168 | currLeftLogNorm = 0; 169 | end 170 | if iVariable < numVariables 171 | currRight = rightPostfixArray{iVariable + 1}; 172 | currRightLogNorm = rightPostfixLogNorm(iVariable + 1); 173 | else 174 | currRight = 1; 175 | currRightLogNorm = 0; 176 | end 177 | 178 | for variableValue = 1 : numValues 179 | for iFactor = 1 : numFactors 180 | currCore = factorCoreArray{iVariable, iFactor}; 181 | [r1, n1, r2] = size(currCore); 182 | cr1 = reshape(currCore(:, variableValue, :), [1, r1, r2, 1]); 183 | tp1{iFactor} = cr1; 184 | end 185 | if isAmenMatrixByVector 186 | if iVariable > 1 187 | leftProd = amen_mv(transpose(tp1), currLeft, roundingPrecision, 'verb', verboseLevel); 188 | else 189 | leftProd = tp1.tt; 190 | end 191 | if iVariable < numVariables 192 | prob = dot(leftProd, currRight); 193 | else 194 | prob = full(leftProd); 195 | end 196 | unaryMarginals(iVariable, variableValue) = prob; 197 | else 198 | unaryMarginals(iVariable, variableValue) = full(currLeft * tp1 * currRight); 199 | end 200 | end 201 | logZ(iVariable) = currLeftLogNorm + currRightLogNorm; 202 | logZ(iVariable) = logZ(iVariable) + log(sum(unaryMarginals(iVariable, :))); 203 | end 204 | 205 | % Normalize marginal distributions. 206 | unaryMarginals = bsxfun(@times, unaryMarginals, 1 ./ sum(unaryMarginals, 2)); 207 | end 208 | -------------------------------------------------------------------------------- /examples/spinglass.uai: -------------------------------------------------------------------------------- 1 | MARKOV 2 | 100 3 | 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 | 280 5 | 2 0 1 6 | 2 0 10 7 | 2 1 2 8 | 2 1 11 9 | 2 2 3 10 | 2 2 12 11 | 2 3 4 12 | 2 3 13 13 | 2 4 5 14 | 2 4 14 15 | 2 5 6 16 | 2 5 15 17 | 2 6 7 18 | 2 6 16 19 | 2 7 8 20 | 2 7 17 21 | 2 8 9 22 | 2 8 18 23 | 2 9 19 24 | 2 10 11 25 | 2 10 20 26 | 2 11 12 27 | 2 11 21 28 | 2 12 13 29 | 2 12 22 30 | 2 13 14 31 | 2 13 23 32 | 2 14 15 33 | 2 14 24 34 | 2 15 16 35 | 2 15 25 36 | 2 16 17 37 | 2 16 26 38 | 2 17 18 39 | 2 17 27 40 | 2 18 19 41 | 2 18 28 42 | 2 19 29 43 | 2 20 21 44 | 2 20 30 45 | 2 21 22 46 | 2 21 31 47 | 2 22 23 48 | 2 22 32 49 | 2 23 24 50 | 2 23 33 51 | 2 24 25 52 | 2 24 34 53 | 2 25 26 54 | 2 25 35 55 | 2 26 27 56 | 2 26 36 57 | 2 27 28 58 | 2 27 37 59 | 2 28 29 60 | 2 28 38 61 | 2 29 39 62 | 2 30 31 63 | 2 30 40 64 | 2 31 32 65 | 2 31 41 66 | 2 32 33 67 | 2 32 42 68 | 2 33 34 69 | 2 33 43 70 | 2 34 35 71 | 2 34 44 72 | 2 35 36 73 | 2 35 45 74 | 2 36 37 75 | 2 36 46 76 | 2 37 38 77 | 2 37 47 78 | 2 38 39 79 | 2 38 48 80 | 2 39 49 81 | 2 40 41 82 | 2 40 50 83 | 2 41 42 84 | 2 41 51 85 | 2 42 43 86 | 2 42 52 87 | 2 43 44 88 | 2 43 53 89 | 2 44 45 90 | 2 44 54 91 | 2 45 46 92 | 2 45 55 93 | 2 46 47 94 | 2 46 56 95 | 2 47 48 96 | 2 47 57 97 | 2 48 49 98 | 2 48 58 99 | 2 49 59 100 | 2 50 51 101 | 2 50 60 102 | 2 51 52 103 | 2 51 61 104 | 2 52 53 105 | 2 52 62 106 | 2 53 54 107 | 2 53 63 108 | 2 54 55 109 | 2 54 64 110 | 2 55 56 111 | 2 55 65 112 | 2 56 57 113 | 2 56 66 114 | 2 57 58 115 | 2 57 67 116 | 2 58 59 117 | 2 58 68 118 | 2 59 69 119 | 2 60 61 120 | 2 60 70 121 | 2 61 62 122 | 2 61 71 123 | 2 62 63 124 | 2 62 72 125 | 2 63 64 126 | 2 63 73 127 | 2 64 65 128 | 2 64 74 129 | 2 65 66 130 | 2 65 75 131 | 2 66 67 132 | 2 66 76 133 | 2 67 68 134 | 2 67 77 135 | 2 68 69 136 | 2 68 78 137 | 2 69 79 138 | 2 70 71 139 | 2 70 80 140 | 2 71 72 141 | 2 71 81 142 | 2 72 73 143 | 2 72 82 144 | 2 73 74 145 | 2 73 83 146 | 2 74 75 147 | 2 74 84 148 | 2 75 76 149 | 2 75 85 150 | 2 76 77 151 | 2 76 86 152 | 2 77 78 153 | 2 77 87 154 | 2 78 79 155 | 2 78 88 156 | 2 79 89 157 | 2 80 81 158 | 2 80 90 159 | 2 81 82 160 | 2 81 91 161 | 2 82 83 162 | 2 82 92 163 | 2 83 84 164 | 2 83 93 165 | 2 84 85 166 | 2 84 94 167 | 2 85 86 168 | 2 85 95 169 | 2 86 87 170 | 2 86 96 171 | 2 87 88 172 | 2 87 97 173 | 2 88 89 174 | 2 88 98 175 | 2 89 99 176 | 2 90 91 177 | 2 91 92 178 | 2 92 93 179 | 2 93 94 180 | 2 94 95 181 | 2 95 96 182 | 2 96 97 183 | 2 97 98 184 | 2 98 99 185 | 1 0 186 | 1 1 187 | 1 2 188 | 1 3 189 | 1 4 190 | 1 5 191 | 1 6 192 | 1 7 193 | 1 8 194 | 1 9 195 | 1 10 196 | 1 11 197 | 1 12 198 | 1 13 199 | 1 14 200 | 1 15 201 | 1 16 202 | 1 17 203 | 1 18 204 | 1 19 205 | 1 20 206 | 1 21 207 | 1 22 208 | 1 23 209 | 1 24 210 | 1 25 211 | 1 26 212 | 1 27 213 | 1 28 214 | 1 29 215 | 1 30 216 | 1 31 217 | 1 32 218 | 1 33 219 | 1 34 220 | 1 35 221 | 1 36 222 | 1 37 223 | 1 38 224 | 1 39 225 | 1 40 226 | 1 41 227 | 1 42 228 | 1 43 229 | 1 44 230 | 1 45 231 | 1 46 232 | 1 47 233 | 1 48 234 | 1 49 235 | 1 50 236 | 1 51 237 | 1 52 238 | 1 53 239 | 1 54 240 | 1 55 241 | 1 56 242 | 1 57 243 | 1 58 244 | 1 59 245 | 1 60 246 | 1 61 247 | 1 62 248 | 1 63 249 | 1 64 250 | 1 65 251 | 1 66 252 | 1 67 253 | 1 68 254 | 1 69 255 | 1 70 256 | 1 71 257 | 1 72 258 | 1 73 259 | 1 74 260 | 1 75 261 | 1 76 262 | 1 77 263 | 1 78 264 | 1 79 265 | 1 80 266 | 1 81 267 | 1 82 268 | 1 83 269 | 1 84 270 | 1 85 271 | 1 86 272 | 1 87 273 | 1 88 274 | 1 89 275 | 1 90 276 | 1 91 277 | 1 92 278 | 1 93 279 | 1 94 280 | 1 95 281 | 1 96 282 | 1 97 283 | 1 98 284 | 1 99 285 | 4 286 | 1.62372872683 0.615866421204 287 | 0.615866421204 1.62372872683 288 | 289 | 4 290 | 1.62372872683 0.615866421204 291 | 0.615866421204 1.62372872683 292 | 293 | 4 294 | 1.55986474662 0.641081223335 295 | 0.641081223335 1.55986474662 296 | 297 | 4 298 | 1.55986474662 0.641081223335 299 | 0.641081223335 1.55986474662 300 | 301 | 4 302 | 1.52821298756 0.654359050824 303 | 0.654359050824 1.52821298756 304 | 305 | 4 306 | 1.52821298756 0.654359050824 307 | 0.654359050824 1.52821298756 308 | 309 | 4 310 | 1.23448551623 0.810054056411 311 | 0.810054056411 1.23448551623 312 | 313 | 4 314 | 1.23448551623 0.810054056411 315 | 0.810054056411 1.23448551623 316 | 317 | 4 318 | 1.0963003788 0.912158765373 319 | 0.912158765373 1.0963003788 320 | 321 | 4 322 | 1.0963003788 0.912158765373 323 | 0.912158765373 1.0963003788 324 | 325 | 4 326 | 1.4678746632 0.681257075328 327 | 0.681257075328 1.4678746632 328 | 329 | 4 330 | 1.4678746632 0.681257075328 331 | 0.681257075328 1.4678746632 332 | 333 | 4 334 | 1.02157600796 0.978879684141 335 | 0.978879684141 1.02157600796 336 | 337 | 4 338 | 1.02157600796 0.978879684141 339 | 0.978879684141 1.02157600796 340 | 341 | 4 342 | 1.20643401328 0.828889097118 343 | 0.828889097118 1.20643401328 344 | 345 | 4 346 | 1.20643401328 0.828889097118 347 | 0.828889097118 1.20643401328 348 | 349 | 4 350 | 1.49049229193 0.670919269702 351 | 0.670919269702 1.49049229193 352 | 353 | 4 354 | 1.49049229193 0.670919269702 355 | 0.670919269702 1.49049229193 356 | 357 | 4 358 | 1.3932855722 0.717727951795 359 | 0.717727951795 1.3932855722 360 | 361 | 4 362 | 1.28367171148 0.779015375234 363 | 0.779015375234 1.28367171148 364 | 365 | 4 366 | 1.28367171148 0.779015375234 367 | 0.779015375234 1.28367171148 368 | 369 | 4 370 | 1.09845217523 0.910371905626 371 | 0.910371905626 1.09845217523 372 | 373 | 4 374 | 1.09845217523 0.910371905626 375 | 0.910371905626 1.09845217523 376 | 377 | 4 378 | 1.45263025962 0.688406422337 379 | 0.688406422337 1.45263025962 380 | 381 | 4 382 | 1.45263025962 0.688406422337 383 | 0.688406422337 1.45263025962 384 | 385 | 4 386 | 1.17337943415 0.852239242395 387 | 0.852239242395 1.17337943415 388 | 389 | 4 390 | 1.17337943415 0.852239242395 391 | 0.852239242395 1.17337943415 392 | 393 | 4 394 | 1.64037522797 0.609616618776 395 | 0.609616618776 1.64037522797 396 | 397 | 4 398 | 1.64037522797 0.609616618776 399 | 0.609616618776 1.64037522797 400 | 401 | 4 402 | 1.34523474369 0.743364683891 403 | 0.743364683891 1.34523474369 404 | 405 | 4 406 | 1.34523474369 0.743364683891 407 | 0.743364683891 1.34523474369 408 | 409 | 4 410 | 1.58198581449 0.63211691966 411 | 0.63211691966 1.58198581449 412 | 413 | 4 414 | 1.58198581449 0.63211691966 415 | 0.63211691966 1.58198581449 416 | 417 | 4 418 | 1.2911876726 0.77448075227 419 | 0.77448075227 1.2911876726 420 | 421 | 4 422 | 1.2911876726 0.77448075227 423 | 0.77448075227 1.2911876726 424 | 425 | 4 426 | 1.01878772558 0.981558743682 427 | 0.981558743682 1.01878772558 428 | 429 | 4 430 | 1.01878772558 0.981558743682 431 | 0.981558743682 1.01878772558 432 | 433 | 4 434 | 1.47590691641 0.677549504568 435 | 0.677549504568 1.47590691641 436 | 437 | 4 438 | 1.58535294687 0.630774366032 439 | 0.630774366032 1.58535294687 440 | 441 | 4 442 | 1.58535294687 0.630774366032 443 | 0.630774366032 1.58535294687 444 | 445 | 4 446 | 1.33220866456 0.750633160257 447 | 0.750633160257 1.33220866456 448 | 449 | 4 450 | 1.33220866456 0.750633160257 451 | 0.750633160257 1.33220866456 452 | 453 | 4 454 | 1.0974721437 0.911184858536 455 | 0.911184858536 1.0974721437 456 | 457 | 4 458 | 1.0974721437 0.911184858536 459 | 0.911184858536 1.0974721437 460 | 461 | 4 462 | 1.37262823794 0.728529380613 463 | 0.728529380613 1.37262823794 464 | 465 | 4 466 | 1.37262823794 0.728529380613 467 | 0.728529380613 1.37262823794 468 | 469 | 4 470 | 1.50587194271 0.664067090724 471 | 0.664067090724 1.50587194271 472 | 473 | 4 474 | 1.50587194271 0.664067090724 475 | 0.664067090724 1.50587194271 476 | 477 | 4 478 | 1.31503849863 0.760434010896 479 | 0.760434010896 1.31503849863 480 | 481 | 4 482 | 1.31503849863 0.760434010896 483 | 0.760434010896 1.31503849863 484 | 485 | 4 486 | 1.0401159087 0.961431309371 487 | 0.961431309371 1.0401159087 488 | 489 | 4 490 | 1.0401159087 0.961431309371 491 | 0.961431309371 1.0401159087 492 | 493 | 4 494 | 1.38321373244 0.722954071775 495 | 0.722954071775 1.38321373244 496 | 497 | 4 498 | 1.38321373244 0.722954071775 499 | 0.722954071775 1.38321373244 500 | 501 | 4 502 | 1.56901032942 0.637344433779 503 | 0.637344433779 1.56901032942 504 | 505 | 4 506 | 1.56901032942 0.637344433779 507 | 0.637344433779 1.56901032942 508 | 509 | 4 510 | 1.35611652281 0.737399761142 511 | 0.737399761142 1.35611652281 512 | 513 | 4 514 | 1.30845886694 0.764257880219 515 | 0.764257880219 1.30845886694 516 | 517 | 4 518 | 1.30845886694 0.764257880219 519 | 0.764257880219 1.30845886694 520 | 521 | 4 522 | 1.24041814984 0.806179754888 523 | 0.806179754888 1.24041814984 524 | 525 | 4 526 | 1.24041814984 0.806179754888 527 | 0.806179754888 1.24041814984 528 | 529 | 4 530 | 1.30780599041 0.764639409311 531 | 0.764639409311 1.30780599041 532 | 533 | 4 534 | 1.30780599041 0.764639409311 535 | 0.764639409311 1.30780599041 536 | 537 | 4 538 | 1.14129125722 0.876200526092 539 | 0.876200526092 1.14129125722 540 | 541 | 4 542 | 1.14129125722 0.876200526092 543 | 0.876200526092 1.14129125722 544 | 545 | 4 546 | 1.06409929361 0.939761924482 547 | 0.939761924482 1.06409929361 548 | 549 | 4 550 | 1.06409929361 0.939761924482 551 | 0.939761924482 1.06409929361 552 | 553 | 4 554 | 1.55589890427 0.642715280058 555 | 0.642715280058 1.55589890427 556 | 557 | 4 558 | 1.55589890427 0.642715280058 559 | 0.642715280058 1.55589890427 560 | 561 | 4 562 | 1.30217367819 0.76794671613 563 | 0.76794671613 1.30217367819 564 | 565 | 4 566 | 1.30217367819 0.76794671613 567 | 0.76794671613 1.30217367819 568 | 569 | 4 570 | 1.1180926936 0.894380229584 571 | 0.894380229584 1.1180926936 572 | 573 | 4 574 | 1.1180926936 0.894380229584 575 | 0.894380229584 1.1180926936 576 | 577 | 4 578 | 1.45419586173 0.687665276953 579 | 0.687665276953 1.45419586173 580 | 581 | 4 582 | 1.45419586173 0.687665276953 583 | 0.687665276953 1.45419586173 584 | 585 | 4 586 | 1.35567521966 0.737639801551 587 | 0.737639801551 1.35567521966 588 | 589 | 4 590 | 1.64160882478 0.609158518706 591 | 0.609158518706 1.64160882478 592 | 593 | 4 594 | 1.64160882478 0.609158518706 595 | 0.609158518706 1.64160882478 596 | 597 | 4 598 | 1.06445327572 0.939449408261 599 | 0.939449408261 1.06445327572 600 | 601 | 4 602 | 1.06445327572 0.939449408261 603 | 0.939449408261 1.06445327572 604 | 605 | 4 606 | 1.45397723207 0.687768678865 607 | 0.687768678865 1.45397723207 608 | 609 | 4 610 | 1.45397723207 0.687768678865 611 | 0.687768678865 1.45397723207 612 | 613 | 4 614 | 1.61265737596 0.620094519086 615 | 0.620094519086 1.61265737596 616 | 617 | 4 618 | 1.61265737596 0.620094519086 619 | 0.620094519086 1.61265737596 620 | 621 | 4 622 | 1.34398393941 0.744056510408 623 | 0.744056510408 1.34398393941 624 | 625 | 4 626 | 1.34398393941 0.744056510408 627 | 0.744056510408 1.34398393941 628 | 629 | 4 630 | 1.13585288588 0.88039570303 631 | 0.88039570303 1.13585288588 632 | 633 | 4 634 | 1.13585288588 0.88039570303 635 | 0.88039570303 1.13585288588 636 | 637 | 4 638 | 1.00336377355 0.996647503489 639 | 0.996647503489 1.00336377355 640 | 641 | 4 642 | 1.00336377355 0.996647503489 643 | 0.996647503489 1.00336377355 644 | 645 | 4 646 | 1.31436001443 0.760826553625 647 | 0.760826553625 1.31436001443 648 | 649 | 4 650 | 1.31436001443 0.760826553625 651 | 0.760826553625 1.31436001443 652 | 653 | 4 654 | 1.60159748453 0.624376605021 655 | 0.624376605021 1.60159748453 656 | 657 | 4 658 | 1.60159748453 0.624376605021 659 | 0.624376605021 1.60159748453 660 | 661 | 4 662 | 1.23421591451 0.810231004352 663 | 0.810231004352 1.23421591451 664 | 665 | 4 666 | 1.48059074835 0.67540608444 667 | 0.67540608444 1.48059074835 668 | 669 | 4 670 | 1.48059074835 0.67540608444 671 | 0.67540608444 1.48059074835 672 | 673 | 4 674 | 1.0240458126 0.976518811659 675 | 0.976518811659 1.0240458126 676 | 677 | 4 678 | 1.0240458126 0.976518811659 679 | 0.976518811659 1.0240458126 680 | 681 | 4 682 | 1.52898367863 0.654029218217 683 | 0.654029218217 1.52898367863 684 | 685 | 4 686 | 1.52898367863 0.654029218217 687 | 0.654029218217 1.52898367863 688 | 689 | 4 690 | 1.12735466285 0.887032300438 691 | 0.887032300438 1.12735466285 692 | 693 | 4 694 | 1.12735466285 0.887032300438 695 | 0.887032300438 1.12735466285 696 | 697 | 4 698 | 1.02253416202 0.977962436022 699 | 0.977962436022 1.02253416202 700 | 701 | 4 702 | 1.02253416202 0.977962436022 703 | 0.977962436022 1.02253416202 704 | 705 | 4 706 | 1.34719888376 0.742280900063 707 | 0.742280900063 1.34719888376 708 | 709 | 4 710 | 1.34719888376 0.742280900063 711 | 0.742280900063 1.34719888376 712 | 713 | 4 714 | 1.27126656262 0.786617086775 715 | 0.786617086775 1.27126656262 716 | 717 | 4 718 | 1.27126656262 0.786617086775 719 | 0.786617086775 1.27126656262 720 | 721 | 4 722 | 1.06773220382 0.936564427316 723 | 0.936564427316 1.06773220382 724 | 725 | 4 726 | 1.06773220382 0.936564427316 727 | 0.936564427316 1.06773220382 728 | 729 | 4 730 | 1.42616629552 0.701180502679 731 | 0.701180502679 1.42616629552 732 | 733 | 4 734 | 1.42616629552 0.701180502679 735 | 0.701180502679 1.42616629552 736 | 737 | 4 738 | 1.24196087447 0.805178343822 739 | 0.805178343822 1.24196087447 740 | 741 | 4 742 | 1.51813434703 0.658703231341 743 | 0.658703231341 1.51813434703 744 | 745 | 4 746 | 1.51813434703 0.658703231341 747 | 0.658703231341 1.51813434703 748 | 749 | 4 750 | 1.06588806596 0.938184816903 751 | 0.938184816903 1.06588806596 752 | 753 | 4 754 | 1.06588806596 0.938184816903 755 | 0.938184816903 1.06588806596 756 | 757 | 4 758 | 1.25017108485 0.799890520678 759 | 0.799890520678 1.25017108485 760 | 761 | 4 762 | 1.25017108485 0.799890520678 763 | 0.799890520678 1.25017108485 764 | 765 | 4 766 | 1.4401450384 0.694374506273 767 | 0.694374506273 1.4401450384 768 | 769 | 4 770 | 1.4401450384 0.694374506273 771 | 0.694374506273 1.4401450384 772 | 773 | 4 774 | 1.51558094086 0.659812995163 775 | 0.659812995163 1.51558094086 776 | 777 | 4 778 | 1.51558094086 0.659812995163 779 | 0.659812995163 1.51558094086 780 | 781 | 4 782 | 1.238472613 0.807446195823 783 | 0.807446195823 1.238472613 784 | 785 | 4 786 | 1.238472613 0.807446195823 787 | 0.807446195823 1.238472613 788 | 789 | 4 790 | 1.63266951538 0.612493827182 791 | 0.612493827182 1.63266951538 792 | 793 | 4 794 | 1.63266951538 0.612493827182 795 | 0.612493827182 1.63266951538 796 | 797 | 4 798 | 1.49239415037 0.670064272062 799 | 0.670064272062 1.49239415037 800 | 801 | 4 802 | 1.49239415037 0.670064272062 803 | 0.670064272062 1.49239415037 804 | 805 | 4 806 | 1.31825669137 0.758577602182 807 | 0.758577602182 1.31825669137 808 | 809 | 4 810 | 1.31825669137 0.758577602182 811 | 0.758577602182 1.31825669137 812 | 813 | 4 814 | 1.08893042808 0.918332314184 815 | 0.918332314184 1.08893042808 816 | 817 | 4 818 | 1.32229836828 0.756258968464 819 | 0.756258968464 1.32229836828 820 | 821 | 4 822 | 1.32229836828 0.756258968464 823 | 0.756258968464 1.32229836828 824 | 825 | 4 826 | 1.0801654997 0.925784058347 827 | 0.925784058347 1.0801654997 828 | 829 | 4 830 | 1.0801654997 0.925784058347 831 | 0.925784058347 1.0801654997 832 | 833 | 4 834 | 1.12556235122 0.888444783992 835 | 0.888444783992 1.12556235122 836 | 837 | 4 838 | 1.12556235122 0.888444783992 839 | 0.888444783992 1.12556235122 840 | 841 | 4 842 | 1.58305805513 0.631688772727 843 | 0.631688772727 1.58305805513 844 | 845 | 4 846 | 1.58305805513 0.631688772727 847 | 0.631688772727 1.58305805513 848 | 849 | 4 850 | 1.64546101647 0.607732416622 851 | 0.607732416622 1.64546101647 852 | 853 | 4 854 | 1.64546101647 0.607732416622 855 | 0.607732416622 1.64546101647 856 | 857 | 4 858 | 1.17631644726 0.850111381451 859 | 0.850111381451 1.17631644726 860 | 861 | 4 862 | 1.17631644726 0.850111381451 863 | 0.850111381451 1.17631644726 864 | 865 | 4 866 | 1.00273925984 0.997268223207 867 | 0.997268223207 1.00273925984 868 | 869 | 4 870 | 1.00273925984 0.997268223207 871 | 0.997268223207 1.00273925984 872 | 873 | 4 874 | 1.1309427893 0.884218025403 875 | 0.884218025403 1.1309427893 876 | 877 | 4 878 | 1.1309427893 0.884218025403 879 | 0.884218025403 1.1309427893 880 | 881 | 4 882 | 1.22470630817 0.816522290553 883 | 0.816522290553 1.22470630817 884 | 885 | 4 886 | 1.22470630817 0.816522290553 887 | 0.816522290553 1.22470630817 888 | 889 | 4 890 | 1.14266974969 0.875143496419 891 | 0.875143496419 1.14266974969 892 | 893 | 4 894 | 1.19123102028 0.83946772958 895 | 0.83946772958 1.19123102028 896 | 897 | 4 898 | 1.19123102028 0.83946772958 899 | 0.83946772958 1.19123102028 900 | 901 | 4 902 | 1.6177116765 0.618157125604 903 | 0.618157125604 1.6177116765 904 | 905 | 4 906 | 1.6177116765 0.618157125604 907 | 0.618157125604 1.6177116765 908 | 909 | 4 910 | 1.49488704064 0.668946865424 911 | 0.668946865424 1.49488704064 912 | 913 | 4 914 | 1.49488704064 0.668946865424 915 | 0.668946865424 1.49488704064 916 | 917 | 4 918 | 1.02020692498 0.980193307373 919 | 0.980193307373 1.02020692498 920 | 921 | 4 922 | 1.02020692498 0.980193307373 923 | 0.980193307373 1.02020692498 924 | 925 | 4 926 | 1.08091166117 0.925144982634 927 | 0.925144982634 1.08091166117 928 | 929 | 4 930 | 1.08091166117 0.925144982634 931 | 0.925144982634 1.08091166117 932 | 933 | 4 934 | 1.01906722637 0.981289530394 935 | 0.981289530394 1.01906722637 936 | 937 | 4 938 | 1.01906722637 0.981289530394 939 | 0.981289530394 1.01906722637 940 | 941 | 4 942 | 1.00972456923 0.990369087247 943 | 0.990369087247 1.00972456923 944 | 945 | 4 946 | 1.00972456923 0.990369087247 947 | 0.990369087247 1.00972456923 948 | 949 | 4 950 | 1.60890855816 0.621539362774 951 | 0.621539362774 1.60890855816 952 | 953 | 4 954 | 1.60890855816 0.621539362774 955 | 0.621539362774 1.60890855816 956 | 957 | 4 958 | 1.27393465094 0.784969620901 959 | 0.784969620901 1.27393465094 960 | 961 | 4 962 | 1.27393465094 0.784969620901 963 | 0.784969620901 1.27393465094 964 | 965 | 4 966 | 1.01082612009 0.989289829502 967 | 0.989289829502 1.01082612009 968 | 969 | 4 970 | 1.35183605604 0.739734670881 971 | 0.739734670881 1.35183605604 972 | 973 | 4 974 | 1.27568683501 0.783891447773 975 | 0.783891447773 1.27568683501 976 | 977 | 4 978 | 1.52439983794 0.655995871367 979 | 0.655995871367 1.52439983794 980 | 981 | 4 982 | 1.50803080147 0.663116429072 983 | 0.663116429072 1.50803080147 984 | 985 | 4 986 | 1.22000148379 0.819671134244 987 | 0.819671134244 1.22000148379 988 | 989 | 4 990 | 1.62905372633 0.613853296448 991 | 0.613853296448 1.62905372633 992 | 993 | 4 994 | 1.32192859348 0.756470512045 995 | 0.756470512045 1.32192859348 996 | 997 | 4 998 | 1.27317111869 0.785440374291 999 | 0.785440374291 1.27317111869 1000 | 1001 | 4 1002 | 1.21865237109 0.820578553589 1003 | 0.820578553589 1.21865237109 1004 | 1005 | 2 1006 | 1.08841549685 1007 | 0.918766778764 1008 | 2 1009 | 1.00391274476 1010 | 0.996102505147 1011 | 2 1012 | 0.953022998014 1013 | 1.04929262157 1014 | 2 1015 | 1.01180926956 1016 | 0.988328561599 1017 | 2 1018 | 0.995825392157 1019 | 1.00419210825 1020 | 2 1021 | 0.96194999757 1022 | 1.03955507306 1023 | 2 1024 | 0.956839646187 1025 | 1.04510719637 1026 | 2 1027 | 0.96610772015 1028 | 1.03508126386 1029 | 2 1030 | 1.00160258517 1031 | 0.998399979002 1032 | 2 1033 | 1.00226740822 1034 | 0.99773772129 1035 | 2 1036 | 0.934243300105 1037 | 1.07038498418 1038 | 2 1039 | 0.932425359171 1040 | 1.07247190369 1041 | 2 1042 | 0.913121546586 1043 | 1.09514445666 1044 | 2 1045 | 1.02453245179 1046 | 0.976054978296 1047 | 2 1048 | 1.03939650722 1049 | 0.962096748504 1050 | 2 1051 | 0.987365020619 1052 | 1.01279666498 1053 | 2 1054 | 1.0454816995 1055 | 0.956496895624 1056 | 2 1057 | 1.03986554209 1058 | 0.961662791508 1059 | 2 1060 | 1.00850171943 1061 | 0.991569950491 1062 | 2 1063 | 1.0741413899 1064 | 0.930976135358 1065 | 2 1066 | 1.01169505577 1067 | 0.988440137467 1068 | 2 1069 | 1.00182233562 1070 | 0.998180979249 1071 | 2 1072 | 1.07038165176 1073 | 0.934246208681 1074 | 2 1075 | 1.01811268597 1076 | 0.982209546916 1077 | 2 1078 | 0.950460291108 1079 | 1.05212180809 1080 | 2 1081 | 1.05979281841 1082 | 0.943580653338 1083 | 2 1084 | 0.937679802192 1085 | 1.06646213096 1086 | 2 1087 | 0.980391362722 1088 | 1.02000082622 1089 | 2 1090 | 1.01612713781 1091 | 0.984128818912 1092 | 2 1093 | 1.03755974836 1094 | 0.963799917621 1095 | 2 1096 | 1.00691536162 1097 | 0.993132132172 1098 | 2 1099 | 1.09459795969 1100 | 0.913577438314 1101 | 2 1102 | 1.09048678863 1103 | 0.917021655311 1104 | 2 1105 | 1.03168508809 1106 | 0.969288023588 1107 | 2 1108 | 1.09436108989 1109 | 0.913775178264 1110 | 2 1111 | 1.01223054645 1112 | 0.987917232403 1113 | 2 1114 | 1.01140299121 1115 | 0.98872557101 1116 | 2 1117 | 1.07867628429 1118 | 0.927062191468 1119 | 2 1120 | 1.01770459102 1121 | 0.982603408514 1122 | 2 1123 | 0.92968431433 1124 | 1.07563393787 1125 | 2 1126 | 0.95275009775 1127 | 1.04959317492 1128 | 2 1129 | 0.988296865746 1130 | 1.01184171949 1131 | 2 1132 | 0.932199155967 1133 | 1.07273214484 1134 | 2 1135 | 1.10104787907 1136 | 0.908225717525 1137 | 2 1138 | 0.966782390735 1139 | 1.0343589308 1140 | 2 1141 | 1.01477163781 1142 | 0.985443387198 1143 | 2 1144 | 1.01734720865 1145 | 0.982948585794 1146 | 2 1147 | 1.02564379165 1148 | 0.974997370575 1149 | 2 1150 | 0.916856126211 1151 | 1.09068366499 1152 | 2 1153 | 1.08110510844 1154 | 0.924979442049 1155 | 2 1156 | 1.04451049653 1157 | 0.957386262104 1158 | 2 1159 | 1.05299492432 1160 | 0.949672193955 1161 | 2 1162 | 0.908539262439 1163 | 1.10066789774 1164 | 2 1165 | 1.002962496 1166 | 0.99704625446 1167 | 2 1168 | 1.03797910041 1169 | 0.963410534567 1170 | 2 1171 | 0.988440936555 1172 | 1.01169423788 1173 | 2 1174 | 1.01247947228 1175 | 0.987674345382 1176 | 2 1177 | 0.968784421087 1178 | 1.0322213882 1179 | 2 1180 | 0.98818706986 1181 | 1.0119541436 1182 | 2 1183 | 0.960544124328 1184 | 1.04107658844 1185 | 2 1186 | 0.958170330088 1187 | 1.04365577664 1188 | 2 1189 | 1.03233889474 1190 | 0.968674148671 1191 | 2 1192 | 1.06223651429 1193 | 0.94140992759 1194 | 2 1195 | 1.04188201529 1196 | 0.959801575728 1197 | 2 1198 | 0.992289301956 1199 | 1.00777061491 1200 | 2 1201 | 1.00993566585 1202 | 0.990162080427 1203 | 2 1204 | 1.01780162317 1205 | 0.982509731995 1206 | 2 1207 | 0.925337590386 1208 | 1.08068667089 1209 | 2 1210 | 0.963388850989 1211 | 1.03800246284 1212 | 2 1213 | 1.09698322044 1214 | 0.911590971832 1215 | 2 1216 | 0.925944448507 1217 | 1.07997839569 1218 | 2 1219 | 1.09771826541 1220 | 0.91098055987 1221 | 2 1222 | 0.926830337876 1223 | 1.07894612329 1224 | 2 1225 | 1.10250942878 1226 | 0.907021721445 1227 | 2 1228 | 0.936982598876 1229 | 1.06725567924 1230 | 2 1231 | 0.927252292492 1232 | 1.07845513901 1233 | 2 1234 | 0.969191160601 1235 | 1.03178819685 1236 | 2 1237 | 0.972840259115 1238 | 1.02791798615 1239 | 2 1240 | 0.941325298076 1241 | 1.06233201428 1242 | 2 1243 | 1.105031773 1244 | 0.904951354733 1245 | 2 1246 | 0.99296743606 1247 | 1.00708237117 1248 | 2 1249 | 1.07531950904 1250 | 0.929956158695 1251 | 2 1252 | 0.944023509122 1253 | 1.05929565348 1254 | 2 1255 | 0.906452874291 1256 | 1.1032013118 1257 | 2 1258 | 1.06306405623 1259 | 0.940677087274 1260 | 2 1261 | 1.03143700548 1262 | 0.969521158045 1263 | 2 1264 | 0.92647221695 1265 | 1.07936318187 1266 | 2 1267 | 1.02830834092 1268 | 0.972470960511 1269 | 2 1270 | 0.927446404747 1271 | 1.078229421 1272 | 2 1273 | 1.01167178668 1274 | 0.988462872217 1275 | 2 1276 | 0.990256205735 1277 | 1.00983966999 1278 | 2 1279 | 0.925497516172 1280 | 1.08049992844 1281 | 2 1282 | 1.01732684089 1283 | 0.982968265268 1284 | 2 1285 | 0.915439347199 1286 | 1.09237166073 1287 | 2 1288 | 0.994461157748 1289 | 1.0055696919 1290 | 2 1291 | 1.07706018741 1292 | 0.928453220803 1293 | 2 1294 | 1.04085117301 1295 | 0.960752147791 1296 | 2 1297 | 0.90527377175 1298 | 1.10463821134 1299 | 2 1300 | 1.09259549373 1301 | 0.915251807042 1302 | 2 1303 | 1.02930597342 1304 | 0.971528414117 1305 | --------------------------------------------------------------------------------