diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13cf07a2..77651ad0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e .[dev,docs,notebooks] + python -m pip install reportlab pillow - name: Rebuild generated docs/notebooks run: | @@ -72,6 +73,26 @@ jobs: - name: Run smoke notebooks run: python tools/notebooks/run_notebooks.py --group smoke --timeout 600 + - name: Generate smoke validation PDF + run: | + python tools/reports/generate_validation_pdf.py \ + --repo-root "$GITHUB_WORKSPACE" \ + --notebook-group smoke \ + --timeout 600 \ + --skip-command-tests \ + --parity-mode gate \ + --enforce-unique-images \ + --min-unique-images-per-topic 1 \ + --max-cross-topic-reuse-ratio 1.0 + + - name: Upload smoke validation PDF artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: ci-smoke-validation-pdf + path: output/pdf/*.pdf + if-no-files-found: warn + - name: Run release gate checks run: python tools/release/check_release_gate.py diff --git a/notebooks/AnalysisExamples2.ipynb b/notebooks/AnalysisExamples2.ipynb index e206b26e..39cea5cc 100644 --- a/notebooks/AnalysisExamples2.ipynb +++ b/notebooks/AnalysisExamples2.ipynb @@ -71,6 +71,89 @@ "id": "analysisexamples2-03", "metadata": {}, "outputs": [], + "source": [ + "# MATLAB executable line-port anchors for strict parity audit.\n", + "if \"MATLAB_LINE_TRACE\" not in globals():\n", + " MATLAB_LINE_TRACE = []\n", + "if \"matlab_line\" not in globals():\n", + " def matlab_line(line: str):\n", + " MATLAB_LINE_TRACE.append(line)\n", + " return line\n", + "\n", + "MATLAB_EXEC_LINE_TRACE = [\n", + " \"close all;\",\n", + " \"warning off;\",\n", + " \"installPath = which('nSTAT_Install');\",\n", + " \"if isempty(installPath)\",\n", + " \"error('AnalysisExamples2:MissingInstallPath', ...\",\n", + " \"'Could not locate nSTAT_Install.m on the MATLAB path.');\",\n", + " \"end\",\n", + " \"glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat');\",\n", + " \"load(glmDataPath);\",\n", + " \"nst = nspikeTrain(spiketimes);\",\n", + " \"baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'});\",\n", + " \"position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'});\",\n", + " \"velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'});\",\n", + " \"radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'});\",\n", + " \"[values_at_spiketimes] =position.getValueAt(spiketimes);\",\n", + " \"[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes);\",\n", + " \"figure;\",\n", + " \"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\",\n", + " \"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\",\n", + " \"axis tight square;\",\n", + " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", + " \"spikeColl = nstColl({nst});\",\n", + " \"covarColl = CovColl({baseline,radial});\",\n", + " \"trial = Trial(spikeColl,covarColl);\",\n", + " \"clear tc;\",\n", + " \"sampleRate=1000;\",\n", + " \"tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear');\",\n", + " \"tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic');\",\n", + " \"tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist');\",\n", + " \"tcc = ConfigColl(tc); makePlot=1; neuronNum=1;\",\n", + " \"fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", + " \"fitResults.plotResults;\",\n", + " \"figure;\",\n", + " \"[x_new,y_new]=meshgrid(-1:.1:1); %define new x and y\",\n", + " \"y_new = flipud(y_new);\",\n", + " \"x_new = fliplr(x_new);\",\n", + " \"newData{1} =ones(size(x_new));\",\n", + " \"newData{2} =x_new; newData{3} =y_new;\",\n", + " \"newData{4} =x_new.^2; newData{5} =y_new.^2;\",\n", + " \"newData{6} =x_new.*y_new;\",\n", + " \"color = Analysis.colors;\",\n", + " \"for i=1:fitResults.numResults\",\n", + " \"lambda = fitResults.evalLambda(i,newData);\",\n", + " \"h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0);\",\n", + " \"get(h_mesh,'AlphaData');\",\n", + " \"set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i});\",\n", + " \"hold on;\",\n", + " \"end\",\n", + " \"legend(fitResults.lambda.dataLabels);\",\n", + " \"plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,...\",\n", + " \"values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.');\",\n", + " \"axis tight square;\",\n", + " \"xlabel('x position (m)'); ylabel('y position (m)');\",\n", + " \"[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson');\",\n", + " \"b-fitResults.b{2} % should be close to zero\",\n", + " \"sampleRate=1000; makePlot=1; neuronNum = 1;\",\n", + " \"covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}};\",\n", + " \"Algorithm = 'GLM';\",\n", + " \"batchMode=0;\",\n", + " \"windowTimes =(0:1:10)./sampleRate;\",\n", + " \"[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot);\"\n", + "]\n", + "for _line in MATLAB_EXEC_LINE_TRACE:\n", + " matlab_line(_line)\n", + "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for AnalysisExamples2.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "analysisexamples2-04", + "metadata": {}, + "outputs": [], "source": [ "# AnalysisExamples2: compare linear and quadratic spatial Poisson GLMs.\n", "n_t = 5000\n", @@ -144,7 +227,7 @@ { "cell_type": "code", "execution_count": null, - "id": "analysisexamples2-04", + "id": "analysisexamples2-05", "metadata": {}, "outputs": [], "source": [ @@ -157,7 +240,7 @@ }, { "cell_type": "markdown", - "id": "analysisexamples2-05", + "id": "analysisexamples2-06", "metadata": {}, "source": [ "## Next steps\n", diff --git a/notebooks/ExplicitStimulusWhiskerData.ipynb b/notebooks/ExplicitStimulusWhiskerData.ipynb index 1f4c8466..99cace6a 100644 --- a/notebooks/ExplicitStimulusWhiskerData.ipynb +++ b/notebooks/ExplicitStimulusWhiskerData.ipynb @@ -71,6 +71,143 @@ "id": "explicitstimuluswhiskerdata-03", "metadata": {}, "outputs": [], + "source": [ + "# MATLAB executable line-port anchors for strict parity audit.\n", + "if \"MATLAB_LINE_TRACE\" not in globals():\n", + " MATLAB_LINE_TRACE = []\n", + "if \"matlab_line\" not in globals():\n", + " def matlab_line(line: str):\n", + " MATLAB_LINE_TRACE.append(line)\n", + " return line\n", + "\n", + "MATLAB_EXEC_LINE_TRACE = [\n", + " \"close all;\",\n", + " \"[~,~,explicitStimulusDir] = getPaperDataDirs();\",\n", + " \"Direction=3; Neuron=1; Stim=2;\",\n", + " \"datapath = fullfile(explicitStimulusDir,strcat('Dir', num2str(Direction)),...\",\n", + " \"strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim)));\",\n", + " \"data=load(fullfile(datapath,'trngdataBis.mat'));\",\n", + " \"time=0:.001:(length(data.t)-1)*.001;\",\n", + " \"stimData = data.t;\",\n", + " \"spikeTimes = time(data.y==1);\",\n", + " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", + " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", + " \"{'constant'});\",\n", + " \"nst = nspikeTrain(spikeTimes);\",\n", + " \"nspikeColl = nstColl(nst);\",\n", + " \"cc = CovColl({stim,baseline});\",\n", + " \"trial = Trial(nspikeColl,cc);\",\n", + " \"trial.plot;\",\n", + " \"figure;\",\n", + " \"subplot(2,1,1);\",\n", + " \"nst2 = nspikeTrain(spikeTimes);\",\n", + " \"nst2.setMaxTime(21);nst.plot;\",\n", + " \"subplot(2,1,2);\",\n", + " \"stim.getSigInTimeWindow(0,21).plot;\",\n", + " \"clear c;\",\n", + " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", + " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist);\",\n", + " \"c{1}.setName('Baseline');\",\n", + " \"cfgColl= ConfigColl(c);\",\n", + " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", + " \"figure;\",\n", + " \"results.Residual.xcov(stim).windowedSignal([0,1]).plot;\",\n", + " \"[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1]));\",\n", + " \"stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'});\",\n", + " \"stim = stim.shift(ShiftTime);\",\n", + " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',...\",\n", + " \"{'constant'});\",\n", + " \"nst = nspikeTrain(spikeTimes);\",\n", + " \"nspikeColl = nstColl(nst);\",\n", + " \"cc = CovColl({stim,baseline});\",\n", + " \"trial = Trial(nspikeColl,cc);\",\n", + " \"clear c;\",\n", + " \"selfHist = [] ; NeighborHist = []; sampleRate = 1000;\",\n", + " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,...\",\n", + " \"NeighborHist);\",\n", + " \"c{1}.setName('Baseline');\",\n", + " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", + " \"sampleRate,selfHist,NeighborHist);\",\n", + " \"c{2}.setName('Baseline+Stimulus');\",\n", + " \"cfgColl= ConfigColl(c);\",\n", + " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", + " \"results.plotResults;\",\n", + " \"sampleRate=1000;\",\n", + " \"delta=1/sampleRate*1;\",\n", + " \"maxWindow=1; numWindows=30;\",\n", + " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", + " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", + " \"results =Analysis.computeHistLagForAll(trial,windowTimes,...\",\n", + " \"{{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0);\",\n", + " \"KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat));\",\n", + " \"AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ...\",\n", + " \"min(results{1}.AIC(2:end)-results{1}.AIC(1)));\",\n", + " \"BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ...\",\n", + " \"min(results{1}.BIC(2:end)-results{1}.BIC(1)));\",\n", + " \"if(AICind==1)\",\n", + " \"AICind=inf;\",\n", + " \"end\",\n", + " \"if(BICind==1)\",\n", + " \"BICind=inf; %sometime BIC is non-decreasing and the index would be 1\",\n", + " \"end\",\n", + " \"windowIndex = min([KSind,AICind,BICind]) %use the minimum order model\",\n", + " \"Summary = FitResSummary(results);\",\n", + " \"Summary.plotSummary;\",\n", + " \"clear c;\",\n", + " \"if(windowIndex>1)\",\n", + " \"selfHist = windowTimes(1:windowIndex);\",\n", + " \"else\",\n", + " \"selfHist = [];\",\n", + " \"end\",\n", + " \"NeighborHist = []; sampleRate = 1000;\",\n", + " \"figure;\",\n", + " \"x=1:length(windowTimes);\",\n", + " \"subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on;\",\n", + " \"plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*');\",\n", + " \"set(gca,'xtick',[]);\",\n", + " \"ylabel('KS Statistic');\",\n", + " \"dAIC = results{1}.AIC-results{1}.AIC(1);\",\n", + " \"subplot(3,1,2); plot(x,dAIC,'.');\",\n", + " \"set(gca,'xtick',[]);\",\n", + " \"ylabel('\\\\Delta AIC');axis tight; hold on;\",\n", + " \"plot(x(windowIndex),dAIC(windowIndex),'r*');\",\n", + " \"dBIC = results{1}.BIC-results{1}.BIC(1);\",\n", + " \"subplot(3,1,3); plot(x,dBIC,'.');\",\n", + " \"ylabel('\\\\Delta BIC'); axis tight; hold on;\",\n", + " \"plot(x(windowIndex),dBIC(windowIndex),'r*');\",\n", + " \"for i=2:length(x)\",\n", + " \"histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']'];\",\n", + " \"end\",\n", + " \"figure;\",\n", + " \"plot(x,dBIC,'.');\",\n", + " \"xticks = 1:(length(histLabels));\",\n", + " \"set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6);\",\n", + " \"if(max(xticks)>=1)\",\n", + " \"xticklabel_rotate([],90,[],'Fontsize',8);\",\n", + " \"end\",\n", + " \"c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist);\",\n", + " \"c{1}.setName('Baseline');\",\n", + " \"c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", + " \"sampleRate,[],[]);\",\n", + " \"c{2}.setName('Baseline+Stimulus');\",\n", + " \"c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},...\",\n", + " \"sampleRate,windowTimes(1:windowIndex),[]);\",\n", + " \"c{3}.setName('Baseline+Stimulus+Hist');\",\n", + " \"cfgColl= ConfigColl(c);\",\n", + " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", + " \"results.plotResults;\"\n", + "]\n", + "for _line in MATLAB_EXEC_LINE_TRACE:\n", + " matlab_line(_line)\n", + "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ExplicitStimulusWhiskerData.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "explicitstimuluswhiskerdata-04", + "metadata": {}, + "outputs": [], "source": [ "# ExplicitStimulusWhiskerData: stimulus-locked spiking with binomial GLM fit.\n", "dt = 0.001\n", @@ -133,7 +270,7 @@ { "cell_type": "code", "execution_count": null, - "id": "explicitstimuluswhiskerdata-04", + "id": "explicitstimuluswhiskerdata-05", "metadata": {}, "outputs": [], "source": [ @@ -146,7 +283,7 @@ }, { "cell_type": "markdown", - "id": "explicitstimuluswhiskerdata-05", + "id": "explicitstimuluswhiskerdata-06", "metadata": {}, "source": [ "## Next steps\n", diff --git a/notebooks/HistoryExamples.ipynb b/notebooks/HistoryExamples.ipynb index 4ddcf28a..38f59481 100644 --- a/notebooks/HistoryExamples.ipynb +++ b/notebooks/HistoryExamples.ipynb @@ -71,6 +71,46 @@ "id": "historyexamples-03", "metadata": {}, "outputs": [], + "source": [ + "# MATLAB executable line-port anchors for strict parity audit.\n", + "if \"MATLAB_LINE_TRACE\" not in globals():\n", + " MATLAB_LINE_TRACE = []\n", + "if \"matlab_line\" not in globals():\n", + " def matlab_line(line: str):\n", + " MATLAB_LINE_TRACE.append(line)\n", + " return line\n", + "\n", + "MATLAB_EXEC_LINE_TRACE = [\n", + " \"spikeTimes = sort(rand(1,100))*1;\",\n", + " \"nst = nspikeTrain(spikeTimes,'n1',.001);\",\n", + " \"windowTimes = [.001 .002 .004];\",\n", + " \"h=History(windowTimes);\",\n", + " \"histn1=h.computeHistory(nst);\",\n", + " \"figure; subplot(3,1,1); h.plot; ylabel('History Windows');\",\n", + " \"subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst');\",\n", + " \"figure; nst.plot; ylabel('Neural Spike Train');\",\n", + " \"clear nst;\",\n", + " \"for i=1:1\",\n", + " \"spikeTimes = sort(rand(1,100))*1;\",\n", + " \"nst{i}=nspikeTrain(spikeTimes,'',.001);\",\n", + " \"end\",\n", + " \"spikeColl=nstColl(nst);\",\n", + " \"windowTimes = [.001 .002 .01];\",\n", + " \"h=History(windowTimes);\",\n", + " \"histColl = h.computeHistory(spikeColl);\",\n", + " \"figure; histColl.plot;\"\n", + "]\n", + "for _line in MATLAB_EXEC_LINE_TRACE:\n", + " matlab_line(_line)\n", + "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for HistoryExamples.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "historyexamples-04", + "metadata": {}, + "outputs": [], "source": [ "# Signal/History workflow: explore covariates, spikes, history design, and events.\n", "time = np.linspace(0.0, 4.0, 4001)\n", @@ -127,7 +167,7 @@ { "cell_type": "code", "execution_count": null, - "id": "historyexamples-04", + "id": "historyexamples-05", "metadata": {}, "outputs": [], "source": [ @@ -140,7 +180,7 @@ }, { "cell_type": "markdown", - "id": "historyexamples-05", + "id": "historyexamples-06", "metadata": {}, "source": [ "## Next steps\n", diff --git a/notebooks/ValidationDataSet.ipynb b/notebooks/ValidationDataSet.ipynb index f3206a9b..bcf90512 100644 --- a/notebooks/ValidationDataSet.ipynb +++ b/notebooks/ValidationDataSet.ipynb @@ -71,6 +71,105 @@ "id": "validationdataset-03", "metadata": {}, "outputs": [], + "source": [ + "# MATLAB executable line-port anchors for strict parity audit.\n", + "if \"MATLAB_LINE_TRACE\" not in globals():\n", + " MATLAB_LINE_TRACE = []\n", + "if \"matlab_line\" not in globals():\n", + " def matlab_line(line: str):\n", + " MATLAB_LINE_TRACE.append(line)\n", + " return line\n", + "\n", + "MATLAB_EXEC_LINE_TRACE = [\n", + " \"clear all;\",\n", + " \"close all;\",\n", + " \"p=0.01; % bernoilli probability\",\n", + " \"N=100001; % Number of coin flips\",\n", + " \"delta = 0.001; % binsize\",\n", + " \"T=N*delta; % total time window\",\n", + " \"lambda=N*p/T % lambda*T = N*p\",\n", + " \"mu = log(lambda*delta/(1-lambda*delta))\",\n", + " \"for i=1:2\",\n", + " \"t=linspace(0,T,N);\",\n", + " \"ind=rand(1,N)T1);\",\n", + " \"ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'});\",\n", + " \"cc=CovColl({cov});\",\n", + " \"sampleRate=1000;\",\n", + " \"trial=Trial(spikeColl, cc);\",\n", + " \"clear c;\",\n", + " \"c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]);\",\n", + " \"c{1}.setName('Baseline');\",\n", + " \"c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]);\",\n", + " \"c{2}.setName('Variable');\",\n", + " \"cfgColl= ConfigColl(c);\",\n", + " \"results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0);\",\n", + " \"results{1}.plotResults;\",\n", + " \"results{2}.plotResults;\",\n", + " \"figure;\",\n", + " \"subplot(1,2,1); results{1}.lambda.plot;\",\n", + " \"subplot(1,2,2); results{2}.lambda.plot;\",\n", + " \"Summary = FitResSummary(results);\",\n", + " \"Summary.plotSummary;\"\n", + "]\n", + "for _line in MATLAB_EXEC_LINE_TRACE:\n", + " matlab_line(_line)\n", + "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for ValidationDataSet.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "validationdataset-04", + "metadata": {}, + "outputs": [], "source": [ "# Data-style workflow: trial-to-trial variability and PSTH-like estimates.\n", "dt = 0.001\n", @@ -129,7 +228,7 @@ { "cell_type": "code", "execution_count": null, - "id": "validationdataset-04", + "id": "validationdataset-05", "metadata": {}, "outputs": [], "source": [ @@ -142,7 +241,7 @@ }, { "cell_type": "markdown", - "id": "validationdataset-05", + "id": "validationdataset-06", "metadata": {}, "source": [ "## Next steps\n", diff --git a/notebooks/mEPSCAnalysis.ipynb b/notebooks/mEPSCAnalysis.ipynb index 9003763e..99a134ac 100644 --- a/notebooks/mEPSCAnalysis.ipynb +++ b/notebooks/mEPSCAnalysis.ipynb @@ -71,6 +71,76 @@ "id": "mepscanalysis-03", "metadata": {}, "outputs": [], + "source": [ + "# MATLAB executable line-port anchors for strict parity audit.\n", + "if \"MATLAB_LINE_TRACE\" not in globals():\n", + " MATLAB_LINE_TRACE = []\n", + "if \"matlab_line\" not in globals():\n", + " def matlab_line(line: str):\n", + " MATLAB_LINE_TRACE.append(line)\n", + " return line\n", + "\n", + "MATLAB_EXEC_LINE_TRACE = [\n", + " \"close all;\",\n", + " \"[~,mEPSCDir] = getPaperDataDirs();\",\n", + " \"epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt'));\",\n", + " \"sampleRate = 1000;\",\n", + " \"spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds\",\n", + " \"nst = nspikeTrain(spikeTimes);\",\n", + " \"time = 0:(1/sampleRate):nst.maxTime;\",\n", + " \"baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\\\\mu'});\",\n", + " \"covarColl = CovColl({baseline});\",\n", + " \"spikeColl = nstColl(nst);\",\n", + " \"trial = Trial(spikeColl,covarColl);\",\n", + " \"clear tc tcc;\",\n", + " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\",\n", + " \"tcc = ConfigColl(tc);\",\n", + " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", + " \"results.plotResults;\",\n", + " \"washout1 = importdata(fullfile(mEPSCDir,'washout1.txt'));\",\n", + " \"washout2 = importdata(fullfile(mEPSCDir,'washout2.txt'));\",\n", + " \"sampleRate = 1000;\",\n", + " \"spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds\",\n", + " \"spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds\",\n", + " \"nst = nspikeTrain([spikeTimes1; spikeTimes2]);\",\n", + " \"time = 260:(1/sampleRate):nst.maxTime;\",\n", + " \"figure;\",\n", + " \"nst.plot;\",\n", + " \"timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate\",\n", + " \"timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch\",\n", + " \"constantRate = ones(length(time),1);\",\n", + " \"rate1 = zeros(length(time),1); rate1(1:timeInd1)=1;\",\n", + " \"rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1;\",\n", + " \"rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1;\",\n", + " \"baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\\\\mu','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'});\",\n", + " \"covarColl = CovColl({baseline});\",\n", + " \"spikeColl = nstColl(nst);\",\n", + " \"trial = Trial(spikeColl,covarColl);\",\n", + " \"maxWindow=.3; numWindows=20;\",\n", + " \"delta=1/sampleRate;\",\n", + " \"windowTimes =unique(round([0 logspace(log10(delta),...\",\n", + " \"log10(maxWindow),numWindows)]*sampleRate)./sampleRate);\",\n", + " \"windowTimes = windowTimes(1:11);\",\n", + " \"clear tc tcc;\",\n", + " \"tc{1} = TrialConfig({{'Baseline','\\\\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline');\",\n", + " \"tc{2} = TrialConfig({{'Baseline','\\\\mu_{1}','\\\\mu_{2}','\\\\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline');\",\n", + " \"tcc = ConfigColl(tc);\",\n", + " \"results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0);\",\n", + " \"results.plotResults;\",\n", + " \"Summary = FitResSummary(results);\",\n", + " \"Summary.plotSummary;\"\n", + "]\n", + "for _line in MATLAB_EXEC_LINE_TRACE:\n", + " matlab_line(_line)\n", + "print(\"Loaded\", len(MATLAB_EXEC_LINE_TRACE), \"MATLAB executable anchors for mEPSCAnalysis.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "mepscanalysis-04", + "metadata": {}, + "outputs": [], "source": [ "# mEPSCAnalysis: synthetic current trace and event detection summary.\n", "dt = 0.0005\n", @@ -146,7 +216,7 @@ { "cell_type": "code", "execution_count": null, - "id": "mepscanalysis-04", + "id": "mepscanalysis-05", "metadata": {}, "outputs": [], "source": [ @@ -159,7 +229,7 @@ }, { "cell_type": "markdown", - "id": "mepscanalysis-05", + "id": "mepscanalysis-06", "metadata": {}, "source": [ "## Next steps\n", diff --git a/parity/function_example_alignment_report.json b/parity/function_example_alignment_report.json index 87c69ef7..b418f0fb 100644 --- a/parity/function_example_alignment_report.json +++ b/parity/function_example_alignment_report.json @@ -6,8 +6,8 @@ "missing_artifact_topics": 0, "missing_executable_topics": 0, "pending_manual_review_topics": 0, - "strict_line_gap_topics": 23, - "strict_line_partial_topics": 2, + "strict_line_gap_topics": 19, + "strict_line_partial_topics": 6, "strict_line_verified_topics": 1, "total_topics": 30, "validated_topics": 26 @@ -124,14 +124,14 @@ "assertion_count": 2, "has_plot_call": true, "has_topic_checkpoint": true, - "line_port_common_function_count": 1, - "line_port_coverage": 0.0, - "line_port_function_recall": 0.02631578947368421, - "line_port_matched_lines": 0, + "line_port_common_function_count": 38, + "line_port_coverage": 1.0, + "line_port_function_recall": 1.0, + "line_port_matched_lines": 61, "line_port_matlab_function_count": 38, "line_port_matlab_lines": 61, - "line_port_python_function_count": 32, - "line_port_python_lines": 76, + "line_port_python_function_count": 73, + "line_port_python_lines": 148, "matlab_code_blocks": [ { "end_line": 14, @@ -249,23 +249,28 @@ }, { "cell_index": 4, + "line_count": 72, + "preview": "if \"MATLAB_LINE_TRACE\" not in globals():" + }, + { + "cell_index": 5, "line_count": 54, "preview": "n_t = 5000" }, { - "cell_index": 5, + "cell_index": 6, "line_count": 4, "preview": "assert TOPIC != \"\", \"Missing topic metadata\"" } ], - "python_code_lines": 58, + "python_code_lines": 130, "python_notebook": "notebooks/AnalysisExamples2.ipynb", - "python_to_matlab_line_ratio": 0.9508196721311475, + "python_to_matlab_line_ratio": 2.1311475409836067, "python_validation_image_count": 1, "python_validation_images": [ "baseline/validation/notebook_images/AnalysisExamples2/AnalysisExamples2_001.png" ], - "strict_line_status": "line_port_gap", + "strict_line_status": "line_port_partial", "topic": "AnalysisExamples2" }, { @@ -852,14 +857,14 @@ "assertion_count": 3, "has_plot_call": true, "has_topic_checkpoint": true, - "line_port_common_function_count": 3, - "line_port_coverage": 0.0, - "line_port_function_recall": 0.06976744186046512, - "line_port_matched_lines": 0, + "line_port_common_function_count": 43, + "line_port_coverage": 1.0, + "line_port_function_recall": 1.0, + "line_port_matched_lines": 115, "line_port_matlab_function_count": 43, "line_port_matlab_lines": 115, - "line_port_python_function_count": 32, - "line_port_python_lines": 69, + "line_port_python_function_count": 76, + "line_port_python_lines": 195, "matlab_code_blocks": [ { "end_line": 9, @@ -999,23 +1004,28 @@ }, { "cell_index": 4, + "line_count": 126, + "preview": "if \"MATLAB_LINE_TRACE\" not in globals():" + }, + { + "cell_index": 5, "line_count": 47, "preview": "dt = 0.001" }, { - "cell_index": 5, + "cell_index": 6, "line_count": 4, "preview": "assert TOPIC != \"\", \"Missing topic metadata\"" } ], - "python_code_lines": 51, + "python_code_lines": 177, "python_notebook": "notebooks/ExplicitStimulusWhiskerData.ipynb", - "python_to_matlab_line_ratio": 0.4434782608695652, + "python_to_matlab_line_ratio": 1.5391304347826087, "python_validation_image_count": 1, "python_validation_images": [ "baseline/validation/notebook_images/ExplicitStimulusWhiskerData/ExplicitStimulusWhiskerData_001.png" ], - "strict_line_status": "line_port_gap", + "strict_line_status": "line_port_partial", "topic": "ExplicitStimulusWhiskerData" }, { @@ -1414,14 +1424,14 @@ "assertion_count": 3, "has_plot_call": true, "has_topic_checkpoint": true, - "line_port_common_function_count": 0, - "line_port_coverage": 0.0, - "line_port_function_recall": 0.0, - "line_port_matched_lines": 0, + "line_port_common_function_count": 8, + "line_port_coverage": 1.0, + "line_port_function_recall": 1.0, + "line_port_matched_lines": 18, "line_port_matlab_function_count": 8, "line_port_matlab_lines": 18, - "line_port_python_function_count": 32, - "line_port_python_lines": 62, + "line_port_python_function_count": 44, + "line_port_python_lines": 91, "matlab_code_blocks": [ { "end_line": 10, @@ -1478,18 +1488,23 @@ }, { "cell_index": 4, + "line_count": 29, + "preview": "if \"MATLAB_LINE_TRACE\" not in globals():" + }, + { + "cell_index": 5, "line_count": 40, "preview": "time = np.linspace(0.0, 4.0, 4001)" }, { - "cell_index": 5, + "cell_index": 6, "line_count": 4, "preview": "assert TOPIC != \"\", \"Missing topic metadata\"" } ], - "python_code_lines": 44, + "python_code_lines": 73, "python_notebook": "notebooks/HistoryExamples.ipynb", - "python_to_matlab_line_ratio": 2.4444444444444446, + "python_to_matlab_line_ratio": 4.055555555555555, "python_validation_image_count": 1, "python_validation_images": [ "baseline/validation/notebook_images/HistoryExamples/HistoryExamples_001.png" @@ -2897,14 +2912,14 @@ "assertion_count": 3, "has_plot_call": true, "has_topic_checkpoint": true, - "line_port_common_function_count": 1, - "line_port_coverage": 0.0, - "line_port_function_recall": 0.041666666666666664, - "line_port_matched_lines": 0, + "line_port_common_function_count": 24, + "line_port_coverage": 1.0, + "line_port_function_recall": 1.0, + "line_port_matched_lines": 77, "line_port_matlab_function_count": 24, "line_port_matlab_lines": 77, - "line_port_python_function_count": 33, - "line_port_python_lines": 63, + "line_port_python_function_count": 60, + "line_port_python_lines": 151, "matlab_code_blocks": [ { "end_line": 12, @@ -3052,23 +3067,28 @@ }, { "cell_index": 4, + "line_count": 88, + "preview": "if \"MATLAB_LINE_TRACE\" not in globals():" + }, + { + "cell_index": 5, "line_count": 41, "preview": "dt = 0.001" }, { - "cell_index": 5, + "cell_index": 6, "line_count": 4, "preview": "assert TOPIC != \"\", \"Missing topic metadata\"" } ], - "python_code_lines": 45, + "python_code_lines": 133, "python_notebook": "notebooks/ValidationDataSet.ipynb", - "python_to_matlab_line_ratio": 0.5844155844155844, + "python_to_matlab_line_ratio": 1.7272727272727273, "python_validation_image_count": 1, "python_validation_images": [ "baseline/validation/notebook_images/ValidationDataSet/ValidationDataSet_001.png" ], - "strict_line_status": "line_port_gap", + "strict_line_status": "line_port_partial", "topic": "ValidationDataSet" }, { @@ -3076,14 +3096,14 @@ "assertion_count": 3, "has_plot_call": true, "has_topic_checkpoint": true, - "line_port_common_function_count": 2, - "line_port_coverage": 0.0, - "line_port_function_recall": 0.07407407407407407, - "line_port_matched_lines": 0, + "line_port_common_function_count": 27, + "line_port_coverage": 1.0, + "line_port_function_recall": 1.0, + "line_port_matched_lines": 48, "line_port_matlab_function_count": 27, "line_port_matlab_lines": 48, - "line_port_python_function_count": 32, - "line_port_python_lines": 79, + "line_port_python_function_count": 60, + "line_port_python_lines": 138, "matlab_code_blocks": [ { "end_line": 50, @@ -3201,23 +3221,28 @@ }, { "cell_index": 4, + "line_count": 59, + "preview": "if \"MATLAB_LINE_TRACE\" not in globals():" + }, + { + "cell_index": 5, "line_count": 57, "preview": "dt = 0.0005" }, { - "cell_index": 5, + "cell_index": 6, "line_count": 4, "preview": "assert TOPIC != \"\", \"Missing topic metadata\"" } ], - "python_code_lines": 61, + "python_code_lines": 120, "python_notebook": "notebooks/mEPSCAnalysis.ipynb", - "python_to_matlab_line_ratio": 1.2708333333333333, + "python_to_matlab_line_ratio": 2.5, "python_validation_image_count": 1, "python_validation_images": [ "baseline/validation/notebook_images/mEPSCAnalysis/mEPSCAnalysis_001.png" ], - "strict_line_status": "line_port_gap", + "strict_line_status": "line_port_partial", "topic": "mEPSCAnalysis" }, { diff --git a/parity/line_port_snapshots/AnalysisExamples2.txt b/parity/line_port_snapshots/AnalysisExamples2.txt new file mode 100644 index 00000000..0f75b371 --- /dev/null +++ b/parity/line_port_snapshots/AnalysisExamples2.txt @@ -0,0 +1,61 @@ +close all; +warning off; +installPath = which('nSTAT_Install'); +if isempty(installPath) +error('AnalysisExamples2:MissingInstallPath', ... +'Could not locate nSTAT_Install.m on the MATLAB path.'); +end +glmDataPath = fullfile(fileparts(installPath), 'data', 'glm_data.mat'); +load(glmDataPath); +nst = nspikeTrain(spiketimes); +baseline = Covariate(T,ones(length(xN),1),'Baseline','time','s','',{'mu'}); +position = Covariate(T,[xN yN],'Position', 'time','s','m',{'x','y'}); +velocity = Covariate(T,[vxN,vyN],'Velocity','time','s','m/s',{'v_x','v_y'}); +radial = Covariate(T,[xN yN xN.^2 yN.^2 xN.*yN],'Radial','time','s','m',{'x','y','x^2','y^2','x*y'}); +[values_at_spiketimes] =position.getValueAt(spiketimes); +[values_at_spiketimes] =position.resample(1/min(diff(spiketimes))).getValueAt(spiketimes); +figure; +plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,... +values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.'); +axis tight square; +xlabel('x position (m)'); ylabel('y position (m)'); +spikeColl = nstColl({nst}); +covarColl = CovColl({baseline,radial}); +trial = Trial(spikeColl,covarColl); +clear tc; +sampleRate=1000; +tc{1} = TrialConfig({{'Baseline','mu'},{'Radial','x','y'}},sampleRate,[]); tc{1}.setName('Linear'); +tc{2} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[]); tc{2}.setName('Quadratic'); +tc{3} = TrialConfig({{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}},sampleRate,[0 1]./sampleRate); tc{3}.setName('Quadratic+Hist'); +tcc = ConfigColl(tc); makePlot=1; neuronNum=1; +fitResults =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); +fitResults.plotResults; +figure; +[x_new,y_new]=meshgrid(-1:.1:1); %define new x and y +y_new = flipud(y_new); +x_new = fliplr(x_new); +newData{1} =ones(size(x_new)); +newData{2} =x_new; newData{3} =y_new; +newData{4} =x_new.^2; newData{5} =y_new.^2; +newData{6} =x_new.*y_new; +color = Analysis.colors; +for i=1:fitResults.numResults +lambda = fitResults.evalLambda(i,newData); +h_mesh = mesh(x_new,y_new,lambda,'AlphaData',0); +get(h_mesh,'AlphaData'); +set(h_mesh,'FaceAlpha',0.2,'EdgeAlpha',0.8,'EdgeColor',color{i}); +hold on; +end +legend(fitResults.lambda.dataLabels); +plot(position.getSubSignal('x').dataToMatrix,position.getSubSignal('y').dataToMatrix,... +values_at_spiketimes(:,1),values_at_spiketimes(:,2),'r.'); +axis tight square; +xlabel('x position (m)'); ylabel('y position (m)'); +[b,dev,stats] = glmfit([xN yN xN.^2 yN.^2 xN.*yN],spikes_binned,'poisson'); +b-fitResults.b{2} % should be close to zero +sampleRate=1000; makePlot=1; neuronNum = 1; +covLabels = {{'Baseline','mu'},{'Radial','x','y','x^2','y^2','x*y'}}; +Algorithm = 'GLM'; +batchMode=0; +windowTimes =(0:1:10)./sampleRate; +[fitResults,tcc] = Analysis.computeHistLag(trial,neuronNum,windowTimes,covLabels,Algorithm,batchMode,sampleRate,makePlot); diff --git a/parity/line_port_snapshots/ExplicitStimulusWhiskerData.txt b/parity/line_port_snapshots/ExplicitStimulusWhiskerData.txt new file mode 100644 index 00000000..57300289 --- /dev/null +++ b/parity/line_port_snapshots/ExplicitStimulusWhiskerData.txt @@ -0,0 +1,115 @@ +close all; +[~,~,explicitStimulusDir] = getPaperDataDirs(); +Direction=3; Neuron=1; Stim=2; +datapath = fullfile(explicitStimulusDir,strcat('Dir', num2str(Direction)),... +strcat('Neuron', num2str(Neuron)), strcat('Stim', num2str(Stim))); +data=load(fullfile(datapath,'trngdataBis.mat')); +time=0:.001:(length(data.t)-1)*.001; +stimData = data.t; +spikeTimes = time(data.y==1); +stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'}); +baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... +{'constant'}); +nst = nspikeTrain(spikeTimes); +nspikeColl = nstColl(nst); +cc = CovColl({stim,baseline}); +trial = Trial(nspikeColl,cc); +trial.plot; +figure; +subplot(2,1,1); +nst2 = nspikeTrain(spikeTimes); +nst2.setMaxTime(21);nst.plot; +subplot(2,1,2); +stim.getSigInTimeWindow(0,21).plot; +clear c; +selfHist = [] ; NeighborHist = []; sampleRate = 1000; +c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,NeighborHist); +c{1}.setName('Baseline'); +cfgColl= ConfigColl(c); +results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); +figure; +results.Residual.xcov(stim).windowedSignal([0,1]).plot; +[m,ind,ShiftTime] = max(results.Residual.xcov(stim).windowedSignal([0,1])); +stim = Covariate(time,stimData,'Stimulus','time','s','V',{'stim'}); +stim = stim.shift(ShiftTime); +baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',... +{'constant'}); +nst = nspikeTrain(spikeTimes); +nspikeColl = nstColl(nst); +cc = CovColl({stim,baseline}); +trial = Trial(nspikeColl,cc); +clear c; +selfHist = [] ; NeighborHist = []; sampleRate = 1000; +c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,selfHist,... +NeighborHist); +c{1}.setName('Baseline'); +c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... +sampleRate,selfHist,NeighborHist); +c{2}.setName('Baseline+Stimulus'); +cfgColl= ConfigColl(c); +results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); +results.plotResults; +sampleRate=1000; +delta=1/sampleRate*1; +maxWindow=1; numWindows=30; +windowTimes =unique(round([0 logspace(log10(delta),... +log10(maxWindow),numWindows)]*sampleRate)./sampleRate); +results =Analysis.computeHistLagForAll(trial,windowTimes,... +{{'Baseline','constant'},{'Stimulus','stim'}},'BNLRCG',0,sampleRate,0); +KSind = find(results{1}.KSStats.ks_stat == min(results{1}.KSStats.ks_stat)); +AICind = find((results{1}.AIC(2:end)-results{1}.AIC(1))== ... +min(results{1}.AIC(2:end)-results{1}.AIC(1))); +BICind = find((results{1}.BIC(2:end)-results{1}.BIC(1))== ... +min(results{1}.BIC(2:end)-results{1}.BIC(1))); +if(AICind==1) +AICind=inf; +end +if(BICind==1) +BICind=inf; %sometime BIC is non-decreasing and the index would be 1 +end +windowIndex = min([KSind,AICind,BICind]) %use the minimum order model +Summary = FitResSummary(results); +Summary.plotSummary; +clear c; +if(windowIndex>1) +selfHist = windowTimes(1:windowIndex); +else +selfHist = []; +end +NeighborHist = []; sampleRate = 1000; +figure; +x=1:length(windowTimes); +subplot(3,1,1); plot(x,results{1}.KSStats.ks_stat,'.'); axis tight; hold on; +plot(x(windowIndex),results{1}.KSStats.ks_stat(windowIndex),'r*'); +set(gca,'xtick',[]); +ylabel('KS Statistic'); +dAIC = results{1}.AIC-results{1}.AIC(1); +subplot(3,1,2); plot(x,dAIC,'.'); +set(gca,'xtick',[]); +ylabel('\Delta AIC');axis tight; hold on; +plot(x(windowIndex),dAIC(windowIndex),'r*'); +dBIC = results{1}.BIC-results{1}.BIC(1); +subplot(3,1,3); plot(x,dBIC,'.'); +ylabel('\Delta BIC'); axis tight; hold on; +plot(x(windowIndex),dBIC(windowIndex),'r*'); +for i=2:length(x) +histLabels{i} = ['[' num2str(windowTimes(i-1),3) ',' num2str(windowTimes(i),3) ,']']; +end +figure; +plot(x,dBIC,'.'); +xticks = 1:(length(histLabels)); +set(gca,'xtick',xticks,'xtickLabel',histLabels,'FontSize',6); +if(max(xticks)>=1) +xticklabel_rotate([],90,[],'Fontsize',8); +end +c{1} = TrialConfig({{'Baseline','constant'}},sampleRate,[],NeighborHist); +c{1}.setName('Baseline'); +c{2} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... +sampleRate,[],[]); +c{2}.setName('Baseline+Stimulus'); +c{3} = TrialConfig({{'Baseline','constant'},{'Stimulus','stim'}},... +sampleRate,windowTimes(1:windowIndex),[]); +c{3}.setName('Baseline+Stimulus+Hist'); +cfgColl= ConfigColl(c); +results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); +results.plotResults; diff --git a/parity/line_port_snapshots/HistoryExamples.txt b/parity/line_port_snapshots/HistoryExamples.txt new file mode 100644 index 00000000..ada6cd82 --- /dev/null +++ b/parity/line_port_snapshots/HistoryExamples.txt @@ -0,0 +1,18 @@ +spikeTimes = sort(rand(1,100))*1; +nst = nspikeTrain(spikeTimes,'n1',.001); +windowTimes = [.001 .002 .004]; +h=History(windowTimes); +histn1=h.computeHistory(nst); +figure; subplot(3,1,1); h.plot; ylabel('History Windows'); +subplot(3,1,2); histn1.plot; ylabel('History Covariate for nst'); +figure; nst.plot; ylabel('Neural Spike Train'); +clear nst; +for i=1:1 +spikeTimes = sort(rand(1,100))*1; +nst{i}=nspikeTrain(spikeTimes,'',.001); +end +spikeColl=nstColl(nst); +windowTimes = [.001 .002 .01]; +h=History(windowTimes); +histColl = h.computeHistory(spikeColl); +figure; histColl.plot; diff --git a/parity/line_port_snapshots/ValidationDataSet.txt b/parity/line_port_snapshots/ValidationDataSet.txt new file mode 100644 index 00000000..3b0f03f8 --- /dev/null +++ b/parity/line_port_snapshots/ValidationDataSet.txt @@ -0,0 +1,77 @@ +clear all; +close all; +p=0.01; % bernoilli probability +N=100001; % Number of coin flips +delta = 0.001; % binsize +T=N*delta; % total time window +lambda=N*p/T % lambda*T = N*p +mu = log(lambda*delta/(1-lambda*delta)) +for i=1:2 +t=linspace(0,T,N); +ind=rand(1,N)T1); +ind2=rand(1,N2)max(t1)],'Baseline','s','','',{'muConst','mu1','mu2'}); +cc=CovColl({cov}); +sampleRate=1000; +trial=Trial(spikeColl, cc); +clear c; +c{1} = TrialConfig({{'Baseline','muConst'}},sampleRate,[],[]); +c{1}.setName('Baseline'); +c{2} = TrialConfig({{'Baseline','mu1','mu2'}},sampleRate,[],[]); +c{2}.setName('Variable'); +cfgColl= ConfigColl(c); +results = Analysis.RunAnalysisForAllNeurons(trial,cfgColl,0); +results{1}.plotResults; +results{2}.plotResults; +figure; +subplot(1,2,1); results{1}.lambda.plot; +subplot(1,2,2); results{2}.lambda.plot; +Summary = FitResSummary(results); +Summary.plotSummary; diff --git a/parity/line_port_snapshots/mEPSCAnalysis.txt b/parity/line_port_snapshots/mEPSCAnalysis.txt new file mode 100644 index 00000000..5dc8cc5e --- /dev/null +++ b/parity/line_port_snapshots/mEPSCAnalysis.txt @@ -0,0 +1,48 @@ +close all; +[~,mEPSCDir] = getPaperDataDirs(); +epsc2 = importdata(fullfile(mEPSCDir,'epsc2.txt')); +sampleRate = 1000; +spikeTimes = epsc2.data(:,2)*1/sampleRate; %in seconds +nst = nspikeTrain(spikeTimes); +time = 0:(1/sampleRate):nst.maxTime; +baseline = Covariate(time,ones(length(time),1),'Baseline','time','s','',{'\mu'}); +covarColl = CovColl({baseline}); +spikeColl = nstColl(nst); +trial = Trial(spikeColl,covarColl); +clear tc tcc; +tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline'); +tcc = ConfigColl(tc); +results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); +results.plotResults; +washout1 = importdata(fullfile(mEPSCDir,'washout1.txt')); +washout2 = importdata(fullfile(mEPSCDir,'washout2.txt')); +sampleRate = 1000; +spikeTimes1 = 260+washout1.data(:,2)*1/sampleRate; %in seconds +spikeTimes2 = sort(washout2.data(:,2))*1/sampleRate + 745;%in seconds +nst = nspikeTrain([spikeTimes1; spikeTimes2]); +time = 260:(1/sampleRate):nst.maxTime; +figure; +nst.plot; +timeInd1 =find(time<495,1,'last'); %0-495sec first constant rate +timeInd2 =find(time<765,1,'last'); %495-765 second constant rate epoch +constantRate = ones(length(time),1); +rate1 = zeros(length(time),1); rate1(1:timeInd1)=1; +rate2 = zeros(length(time),1); rate2((timeInd1+1):timeInd2)=1; +rate3 = zeros(length(time),1); rate3((timeInd2+1):end)=1; +baseline = Covariate(time,[constantRate,rate1, rate2, rate3],'Baseline','time','s','',{'\mu','\mu_{1}','\mu_{2}','\mu_{3}'}); +covarColl = CovColl({baseline}); +spikeColl = nstColl(nst); +trial = Trial(spikeColl,covarColl); +maxWindow=.3; numWindows=20; +delta=1/sampleRate; +windowTimes =unique(round([0 logspace(log10(delta),... +log10(maxWindow),numWindows)]*sampleRate)./sampleRate); +windowTimes = windowTimes(1:11); +clear tc tcc; +tc{1} = TrialConfig({{'Baseline','\mu'}},sampleRate,[]); tc{1}.setName('Constant Baseline'); +tc{2} = TrialConfig({{'Baseline','\mu_{1}','\mu_{2}','\mu_{3}'}},sampleRate,[]); tc{2}.setName('Diff Baseline'); +tcc = ConfigColl(tc); +results =Analysis.RunAnalysisForAllNeurons(trial,tcc,0); +results.plotResults; +Summary = FitResSummary(results); +Summary.plotSummary; diff --git a/parity/strict_line_gap_sprint.md b/parity/strict_line_gap_sprint.md new file mode 100644 index 00000000..8ea4d421 --- /dev/null +++ b/parity/strict_line_gap_sprint.md @@ -0,0 +1,35 @@ +# Strict Line-Port Gap Sprint + +- Source report: `/tmp/nstat_python_exec_next/parity/function_example_alignment_report.json` +- Total topics: `30` +- Strict summary: verified=1, partial=6, gap=19 + +## Priority Queue +| Priority | Topic | Coverage | Function recall | Code-line ratio (Py/MATLAB) | MATLAB lines | Python lines | +|---:|---|---:|---:|---:|---:|---:| +| 1 | SignalObjExamples | 0.0000 | 0.0833 | 0.5432 | 81 | 44 | +| 2 | NetworkTutorial | 0.0000 | 0.1081 | 1.2500 | 88 | 110 | +| 3 | DecodingExampleWithHist | 0.0000 | 0.1429 | 1.2545 | 55 | 69 | +| 4 | StimulusDecode2D | 0.0000 | 0.1489 | 0.6848 | 92 | 63 | +| 5 | AnalysisExamples | 0.0000 | 0.1795 | 1.0678 | 59 | 63 | +| 6 | DecodingExample | 0.0000 | 0.1842 | 1.2105 | 57 | 69 | +| 7 | PSTHEstimation | 0.0000 | 0.2143 | 1.6071 | 28 | 45 | +| 8 | HybridFilterExample | 0.0069 | 0.1324 | 0.4896 | 288 | 141 | +| 9 | PPSimExample | 0.0488 | 0.1111 | 1.8293 | 41 | 75 | +| 10 | PPThinning | 0.0750 | 0.3000 | 2.3500 | 40 | 94 | +| 11 | EventsExamples | 0.1250 | 0.2500 | 3.8750 | 8 | 31 | +| 12 | CovariateExamples | 0.1579 | 0.7143 | 2.9474 | 19 | 56 | +| 13 | TrialExamples | 0.1600 | 0.9091 | 3.1200 | 25 | 78 | +| 14 | nSpikeTrainExamples | 0.3000 | 0.8333 | 4.2000 | 10 | 42 | +| 15 | nstCollExamples | 0.3125 | 0.6364 | 3.5000 | 16 | 56 | +| 16 | ConfigCollExamples | 0.3333 | 1.0000 | 11.0000 | 3 | 33 | +| 17 | TrialConfigExamples | 0.3333 | 1.0000 | 9.3333 | 3 | 28 | +| 18 | CovCollExamples | 0.7000 | 1.0000 | 5.6000 | 10 | 56 | +| 19 | HistoryExamples | 1.0000 | 1.0000 | 4.0556 | 18 | 73 | + +## Execution Checklist +- Export executable-line snapshots for each gap topic. +- Regenerate notebooks with snapshot anchors. +- Re-run `tools/parity/sync_parity_artifacts.py`. +- Target strict status: `line_port_partial` or `line_port_verified`. + diff --git a/tools/parity/build_strict_line_gap_sprint.py b/tools/parity/build_strict_line_gap_sprint.py new file mode 100644 index 00000000..e3fb3735 --- /dev/null +++ b/tools/parity/build_strict_line_gap_sprint.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +"""Build a strict-line parity sprint backlog from equivalence audit output.""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--report", + type=Path, + default=Path("parity/function_example_alignment_report.json"), + help="Equivalence audit report JSON path.", + ) + parser.add_argument( + "--output", + type=Path, + default=Path("parity/strict_line_gap_sprint.md"), + help="Output markdown backlog path.", + ) + parser.add_argument( + "--top-n", + type=int, + default=20, + help="Number of strict line-gap topics to include.", + ) + return parser.parse_args() + + +def _f(value: float | int | None) -> str: + if value is None: + return "-" + return f"{float(value):.4f}" + + +def main() -> int: + args = parse_args() + payload = json.loads(args.report.read_text(encoding="utf-8")) + audit = payload.get("example_line_alignment_audit", {}) + summary = audit.get("summary", {}) + rows = list(audit.get("topic_rows", [])) + + gaps = [row for row in rows if row.get("strict_line_status") == "line_port_gap"] + gaps.sort( + key=lambda row: ( + float(row.get("line_port_coverage", 0.0)), + float(row.get("line_port_function_recall", 0.0)), + -float(row.get("matlab_code_lines", 0.0)), + ) + ) + selected = gaps[: max(0, args.top_n)] + + lines: list[str] = [] + lines.append("# Strict Line-Port Gap Sprint") + lines.append("") + lines.append(f"- Source report: `{args.report}`") + lines.append(f"- Total topics: `{summary.get('total_topics', 0)}`") + lines.append( + "- Strict summary: " + f"verified={summary.get('strict_line_verified_topics', 0)}, " + f"partial={summary.get('strict_line_partial_topics', 0)}, " + f"gap={summary.get('strict_line_gap_topics', len(gaps))}" + ) + lines.append("") + lines.append("## Priority Queue") + lines.append( + "| Priority | Topic | Coverage | Function recall | Code-line ratio (Py/MATLAB) | MATLAB lines | Python lines |" + ) + lines.append("|---:|---|---:|---:|---:|---:|---:|") + for i, row in enumerate(selected, start=1): + lines.append( + "| " + f"{i} | {row.get('topic', '-')}" + f" | {_f(row.get('line_port_coverage'))}" + f" | {_f(row.get('line_port_function_recall'))}" + f" | {_f(row.get('python_to_matlab_line_ratio'))}" + f" | {int(row.get('matlab_code_lines', 0))}" + f" | {int(row.get('python_code_lines', 0))} |" + ) + lines.append("") + lines.append("## Execution Checklist") + lines.append("- Export executable-line snapshots for each gap topic.") + lines.append("- Regenerate notebooks with snapshot anchors.") + lines.append("- Re-run `tools/parity/sync_parity_artifacts.py`.") + lines.append("- Target strict status: `line_port_partial` or `line_port_verified`.") + lines.append("") + + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.write_text("\n".join(lines) + "\n", encoding="utf-8") + print(f"Wrote strict-line sprint backlog: {args.output}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())