Skip to content

Commit 2a8d8e4

Browse files
committed
Fix bug that made IC-TFCE a little slower
1 parent 5ab1f58 commit 2a8d8e4

27 files changed

+496
-202
lines changed

.DS_Store

0 Bytes
Binary file not shown.

TFCE_Benchmarkin/compare_TFCE_speeds.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
%% This script compares TFCE speeds between different implementations
1+
%% This script compares TFCE speeds between different implementations
22

33
% Guarantee there is no behind the scenes parallelization
44
maxNumCompThreads(1);
Lines changed: 112 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,127 @@
1-
%% TFCE vs Fast_TFCE Speed Comparison Script
2-
% This script compares the speed of TFCE and Fast_TFCE methods across different dh values
3-
% to assess the performance gains.
4-
5-
% Clear workspace but keep important variables
6-
vars = who;
7-
vars(strcmp(vars, 'data_matrix')) = [];
8-
vars(strcmp(vars, 'testing_yml_workflow')) = [];
9-
clear(vars{:});
10-
clc;
11-
12-
% Initialize methods to compare
13-
fast_tfce_methods = {'Fast_TFCE_dh1', 'Fast_TFCE_dh5', 'Fast_TFCE_dh50', 'Fast_TFCE_dh100', 'Fast_TFCE_dh250'};
14-
tfce_methods = {'TFCE_dh1', 'TFCE_dh5', 'TFCE_dh50', 'TFCE_dh100', 'TFCE_dh250'};
15-
dh_values = [1, 5, 50, 100, 250]; % dh values for each method
16-
17-
% Combine all methods
18-
all_methods = [fast_tfce_methods, tfce_methods];
19-
20-
% Get the directory of the current script
21-
current_script_dir = fileparts(mfilename('fullpath'));
22-
parent_dir = fileparts(current_script_dir);
23-
24-
% Change the current working directory to the parent directory
25-
cd(parent_dir);
26-
27-
% Create the full path for the results directory - using a different folder
28-
speed_results_dir = './power_calculator_results/tfce_speed_dh_test/';
29-
if ~exist(speed_results_dir, 'dir')
30-
mkdir(speed_results_dir);
31-
end
32-
33-
% Define path for speed comparison results file
34-
speed_comparison_filepath = fullfile(speed_results_dir, 'tfce_speed_test_.mat');
35-
36-
% Check if results already exist
37-
if exist(speed_comparison_filepath, 'file')
38-
error('Delete or remove old file to continue')
39-
else
40-
fprintf('No existing speed comparison results found. Starting fresh.\n');
41-
speed_results = struct();
42-
end
43-
44-
% Define path to clear
45-
clear_dir = fullfile(speed_results_dir, 'hcp_fc');
46-
if ~exist(clear_dir, 'dir')
47-
mkdir(clear_dir);
48-
end
49-
50-
% Set up parameters
51-
fprintf('\n========================================\n');
52-
fprintf('Starting TFCE vs Fast_TFCE dh Speed Comparison\n');
53-
fprintf('========================================\n\n');
54-
55-
% Set parameters
56-
Params = setparams();
57-
Params.testing = false;
58-
Params.save_directory = speed_results_dir;
59-
Params.data_dir = './data/s_hcp_fc_noble_tasks.mat';
60-
Params.all_cluster_stat_types = all_methods; % All methods at once
61-
Params.n_perms = 100; % Reduced number of permutations since we're just comparing speed
62-
Params.n_repetitions = 10; % Reduced number of repetitions
63-
Params.list_of_nsubset = {20}; % Using 20 subjects
64-
Params.save_significance_thresh = 0.15;
65-
66-
% ADD HERE: Skip tests on parameters if needed
67-
% Params.skip_param_tests = true;
68-
69-
% Run the analysis
70-
rep_cal_function(Params);
71-
72-
% Find and load the results files
73-
result_files = dir(fullfile(speed_results_dir, 'hcp_fc', 'hcp_fc*.mat'));
74-
if isempty(result_files)
75-
error('No result files found for %d repetitions', Params.n_repetitions);
1+
%% TFCE Speed Comparison - LaTeX Table Generator
2+
% Generates LaTeX tables for IC-TFCE vs TFCE speed comparison
3+
4+
clear; clc;
5+
6+
% Directory with result files
7+
results_dir = '/Users/f.cravogomes/Desktop/Cloned Repos/PRISME-Brain-Power-Calculator/power_calculator_results/re_tfce_speed_comp';
8+
9+
% Method names
10+
ic_tfce_methods = {'IC_TFCE_FC_cpp_dh1', 'IC_TFCE_FC_cpp_dh5', 'IC_TFCE_FC_cpp_dh10', 'IC_TFCE_FC_cpp_dh25'};
11+
tfce_methods = {'TFCE_cpp_dh1', 'TFCE_cpp_dh5', 'TFCE_cpp_dh10', 'TFCE_cpp_dh25'};
12+
exact_method = 'Exact_FC_TFCE_cpp';
13+
dh_values = [1, 5, 10, 25];
14+
n_subs_list = [20, 80, 200];
15+
16+
% Load all result files
17+
result_files = dir(fullfile(results_dir, '**/*.mat'));
18+
fprintf('Found %d result files\n', length(result_files));
19+
20+
% Initialize storage
21+
ic_tfce_times = struct();
22+
tfce_times = struct();
23+
exact_tfce_times = struct();
24+
25+
for ns = n_subs_list
26+
key = sprintf('n%d', ns);
27+
ic_tfce_times.(key) = cell(1, length(dh_values));
28+
tfce_times.(key) = cell(1, length(dh_values));
29+
exact_tfce_times.(key) = [];
30+
for i = 1:length(dh_values)
31+
ic_tfce_times.(key){i} = [];
32+
tfce_times.(key){i} = [];
33+
end
7634
end
7735

78-
fprintf('Found %d result files. Loading all tasks...\n', length(result_files));
79-
80-
% Initialize the results structure
81-
speed_results = struct();
82-
speed_results.tasks = {};
83-
speed_results.dh_values = dh_values;
84-
85-
% Create structures to store timing data across all tasks
86-
all_fast_tfce_times = zeros(length(fast_tfce_methods), length(result_files));
87-
all_tfce_times = zeros(length(tfce_methods), length(result_files));
88-
task_names = cell(1, length(result_files));
89-
90-
% Process all result files
91-
for file_idx = 1:length(result_files)
92-
temp_file_path = fullfile(result_files(file_idx).folder, result_files(file_idx).name);
93-
temp_results = load(temp_file_path);
36+
% Process each file
37+
for f = 1:length(result_files)
38+
filepath = fullfile(result_files(f).folder, result_files(f).name);
39+
data = load(filepath);
9440

95-
% Get the task name
96-
task_name = strcat(temp_results.meta_data.test_components{1}, '_', ...
97-
temp_results.meta_data.test_components{2});
98-
task_names{file_idx} = task_name;
41+
if ~isfield(data, 'meta_data') || ~isfield(data.meta_data, 'n_subs')
42+
continue;
43+
end
9944

100-
% Extract Fast_TFCE times for this task
101-
for m = 1:length(fast_tfce_methods)
102-
method = fast_tfce_methods{m};
103-
if isfield(temp_results, method) && isfield(temp_results.(method), 'total_time')
104-
all_fast_tfce_times(m, file_idx) = temp_results.(method).total_time;
105-
else
106-
all_fast_tfce_times(m, file_idx) = NaN;
107-
end
45+
n_subs = data.meta_data.n_subs;
46+
key = sprintf('n%d', n_subs);
47+
48+
if ~ismember(n_subs, n_subs_list)
49+
continue;
10850
end
10951

110-
% Extract TFCE times for this task
111-
for m = 1:length(tfce_methods)
112-
method = tfce_methods{m};
113-
if isfield(temp_results, method) && isfield(temp_results.(method), 'total_time')
114-
all_tfce_times(m, file_idx) = temp_results.(method).total_time;
115-
else
116-
all_tfce_times(m, file_idx) = NaN;
52+
% Extract times for each dh value
53+
for i = 1:length(dh_values)
54+
if isfield(data, ic_tfce_methods{i}) && isfield(data.(ic_tfce_methods{i}), 'total_time')
55+
ic_tfce_times.(key){i}(end+1) = data.(ic_tfce_methods{i}).total_time;
56+
end
57+
if isfield(data, tfce_methods{i}) && isfield(data.(tfce_methods{i}), 'total_time')
58+
tfce_times.(key){i}(end+1) = data.(tfce_methods{i}).total_time;
11759
end
11860
end
119-
120-
speed_results.all_fast_tfce_times = all_fast_tfce_times;
121-
speed_results.all_tfce_times = all_tfce_times;
61+
62+
% Extract Exact TFCE time
63+
if isfield(data, exact_method) && isfield(data.(exact_method), 'total_time')
64+
exact_tfce_times.(key)(end+1) = data.(exact_method).total_time;
65+
end
12266
end
12367

124-
% Store all task names
125-
speed_results.tasks = task_names;
68+
% Generate LaTeX output
69+
fprintf('\n\n%% ========== COPY BELOW ==========\n\n');
12670

127-
% Calculate average times across all tasks
128-
speed_results.fast_tfce_times = nanmean(all_fast_tfce_times, 2)';
129-
speed_results.tfce_times = nanmean(all_tfce_times, 2)';
71+
fprintf('\\begin{table}[h!]\n');
72+
fprintf('\\centering\n');
73+
fprintf('\\caption{Runtime comparison of TFCE implementations across varying sample sizes.}\n');
74+
fprintf('\\label{tab:tfce_comparison}\n\n');
13075

131-
% Calculate speed gain (time difference and percentage)
132-
speed_results.speed_gain = zeros(1, length(dh_values));
76+
labels = {'(a)', '(b)', '(c)'};
13377

134-
for i = 1:length(dh_values)
135-
speed_results.speed_gain(i) = speed_results.tfce_times(i)/speed_results.fast_tfce_times(i);
78+
for ns_idx = 1:length(n_subs_list)
79+
ns = n_subs_list(ns_idx);
80+
key = sprintf('n%d', ns);
81+
82+
fprintf('\\vspace{0.5em}\n');
83+
fprintf('\\textbf{%s N = %d}\n\n', labels{ns_idx}, ns);
84+
fprintf('\\begin{tabular}{cccc}\n');
85+
fprintf('\\hline\n');
86+
fprintf('dh & IC\\_TFCE (s) & TFCE (s) & Speedup \\\\\n');
87+
fprintf('\\hline\n');
88+
89+
for i = 1:length(dh_values)
90+
ic_mean = mean(ic_tfce_times.(key){i});
91+
tfce_mean = mean(tfce_times.(key){i});
92+
speedup = tfce_mean / ic_mean;
93+
fprintf('%d & %.4f & %.4f & %.2fx \\\\\n', dh_values(i), ic_mean, tfce_mean, speedup);
94+
end
95+
96+
fprintf('\\hline\n');
97+
fprintf('\\end{tabular}\n\n');
13698
end
13799

138-
% Save the speed comparison results
139-
save(speed_comparison_filepath, 'speed_results');
100+
% Exact TFCE table - by subject size
101+
fprintf('\\vspace{0.5em}\n');
102+
fprintf('\\textbf{(d) Exact TFCE}\n\n');
103+
fprintf('\\begin{tabular}{cccc}\n');
104+
fprintf('\\hline\n');
105+
fprintf('N & Exact TFCE (s) & \\begin{tabular}[c]{@{}c@{}}Speedup\\\\IC-TFCE\\end{tabular} & \\begin{tabular}[c]{@{}c@{}}Speedup\\\\TFCE\\end{tabular} \\\\\n');
106+
fprintf('\\hline\n');
107+
108+
for ns_idx = 1:length(n_subs_list)
109+
ns = n_subs_list(ns_idx);
110+
key = sprintf('n%d', ns);
111+
112+
exact_mean = mean(exact_tfce_times.(key));
113+
% Compare to dh=1 (finest discretization)
114+
ic_mean_dh1 = mean(ic_tfce_times.(key){1});
115+
tfce_mean_dh1 = mean(tfce_times.(key){1});
116+
117+
speedup_ic = exact_mean / ic_mean_dh1;
118+
speedup_tfce = exact_mean / tfce_mean_dh1;
119+
120+
fprintf('%d & %.4f & %.2fx & %.2fx \\\\\n', ns, exact_mean, speedup_ic, speedup_tfce);
121+
end
122+
123+
fprintf('\\hline\n');
124+
fprintf('\\end{tabular}\n\n');
125+
fprintf('\\end{table}\n');
126+
127+
fprintf('\n%% ========== END COPY ==========\n');

data_fit_scripts/fit_power_curve.m

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,41 @@
1919
lb = p.Results.lower_bounds;
2020
ub = p.Results.upper_bounds;
2121

22-
% Initial parameter estimates
23-
% a: roughly where we expect decent power (median of x range)
24-
% b: start with exponential shape (b=1)
2522
a_init = median(results_x);
2623
b_init = 1;
2724
c_init = 50;
2825

29-
% Initial guess: [scale, shape]
26+
% Initial parameter estimates
27+
% a: roughly where we expect decent power (median of x range)
28+
% b: start with exponential shape (b=1)
3029
initial_params = [a_init, b_init, c_init];
3130

3231
% Define cost function (sum of squared residuals)
3332
cost_func = @(params) sum((results_y - power_func(params, results_x)).^2);
3433

3534
% Set optimization options with bounds to ensure positive parameters
36-
options = optimset('Display', 'off', 'MaxFunEvals', 10000);
37-
38-
if exist('fmincon', 'file')
39-
[fitted_params, ~] = fmincon(cost_func, initial_params, [], [], [], [], lb, ub, [], options);
40-
else
41-
% Fallback to fminsearch if Optimization Toolbox not available
42-
[fitted_params, ~] = fminsearch(cost_func, initial_params, options);
43-
end
44-
35+
options = optimoptions('fmincon', ...
36+
'Display', 'off', ...
37+
'MaxFunctionEvaluations', 10000, ...
38+
'MaxIterations', 5000, ...
39+
'OptimalityTolerance', 1e-8, ...
40+
'StepTolerance', 1e-10, ...
41+
'Algorithm', 'interior-point');
42+
43+
[fitted_params, ~] = fmincon(cost_func, initial_params, [], [], [], [], lb, ub, [], options);
44+
4545

4646
% Generate smooth curve for plotting
4747
x = linspace(0, max(results_x), 200);
4848
y = power_func(fitted_params, x);
49-
49+
50+
% Clip power values to avoid weird fits
51+
y = max(0, min(100, y));
52+
5053
% Calculate R-squared
5154
y_pred = power_func(fitted_params, results_x);
5255
ss_res = sum((results_y - y_pred).^2);
5356
ss_tot = sum((results_y - mean(results_y)).^2);
5457
r_squared = 1 - (ss_res / ss_tot);
5558

56-
57-
5859
end

file_handlers/get_variable_type_from_meta_data.m

Whitespace-only changes.

get_variable_type_from_meta_data.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function variable_type = get_variable_type_from_meta_data(meta_data)
2+
3+
if isfield(meta_data, 'variable_type')
4+
variable_type = meta_data.variable_type;
5+
return;
6+
end
7+
8+
end

plot_scripts/.DS_Store

0 Bytes
Binary file not shown.

plot_scripts/average_heat_map_gen.m

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
average_heat_map_gen(method, n_subs, directory, varargin)
33
%
44
% For the paper: Shitf - down to select for paste
5-
% - average_heat_map_gen('Constrained_FDR',80,'/Users/f.cravogomes/Desktop/Pc_Res_Updated/SHOCK Paper Results/power_calculation/hcp_fc')
6-
% - average_heat_map_gen('Size_cpp',500,'/Users/f.cravogomes/Desktop/Pc_Res_Updated/SHOCK Paper Results/power_calculation/abcd_100_sex/')
5+
% - average_heat_map_gen('Constrained_FDR',80,'/Users/f.cravogomes/Desktop/Pc_Res_Updated/PRISME Paper Results/power_calculation/hcp_fc')
6+
% - average_heat_map_gen('Size_cpp',500,'/Users/f.cravogomes/Desktop/Pc_Res_Updated/PRISME Paper Results/power_calculation/abcd_100_sex')
77

88
% Create parser object
99
p = inputParser;
@@ -123,9 +123,12 @@
123123
end
124124

125125
% Figure config
126-
figure('Position', [100, 100, 800, 700]);
126+
figure('Position', [100, 100, 800, 700], 'Color', 'white');
127127

128128
imagesc(power_data);
129+
130+
set(gca, 'XTickLabel', []);
131+
set(gca, 'YTickLabel', []);
129132

130133
c = colorbar;
131134
c.FontSize = 12;

0 commit comments

Comments
 (0)