From 420c25d8e640aa42a618ff0194b6effc76249666 Mon Sep 17 00:00:00 2001 From: zhoupc Date: Fri, 19 Oct 2018 20:10:23 -0400 Subject: [PATCH] fix a bug in oasis_matlab --- OASIS_matlab | 2 +- deconvolveCa/LICENSE | 674 ------------------ deconvolveCa/MCMC/.gitignore | 4 - deconvolveCa/MCMC/README.md | 47 -- deconvolveCa/MCMC/cont_ca_sampler.m | 420 ----------- deconvolveCa/MCMC/license.txt | 339 --------- deconvolveCa/MCMC/plot_continuous_samples.m | 143 ---- deconvolveCa/MCMC/sampling_demo_ar2.m | 64 -- deconvolveCa/MCMC/utilities/HMC_exact2.m | 229 ------ deconvolveCa/MCMC/utilities/addSpike.m | 65 -- .../MCMC/utilities/get_initial_sample.m | 51 -- deconvolveCa/MCMC/utilities/get_next_spikes.m | 159 ----- deconvolveCa/MCMC/utilities/lambda_rate.m | 8 - deconvolveCa/MCMC/utilities/make_G_matrix.m | 23 - .../MCMC/utilities/make_mean_sample.m | 58 -- deconvolveCa/MCMC/utilities/plot_marginals.m | 58 -- deconvolveCa/MCMC/utilities/removeSpike.m | 63 -- deconvolveCa/MCMC/utilities/replaceSpike.m | 73 -- .../MCMC/utilities/samples_cell2mat.m | 24 - deconvolveCa/MCMC/utilities/tau_c2d.m | 15 - deconvolveCa/MCMC/utilities/tau_d2c.m | 15 - deconvolveCa/MCMC/wrapper.m | 13 - deconvolveCa/README.md | 45 -- deconvolveCa/constrained-foopsi/.gitignore | 3 - deconvolveCa/constrained-foopsi/MCEM_foopsi.m | 135 ---- deconvolveCa/constrained-foopsi/README.md | 69 -- .../constrained-foopsi/acknowledgements.txt | 1 - .../constrained-foopsi/constrained_foopsi.m | 298 -------- deconvolveCa/constrained-foopsi/cvx_foopsi.m | 46 -- .../lars_regression_noise.m | 286 -------- deconvolveCa/constrained-foopsi/license.txt | 339 --------- deconvolveCa/deconvolveCa.m | 328 --------- deconvolveCa/examples/Paper/fig1.m | 36 - deconvolveCa/examples/Paper/fig2.m | 17 - deconvolveCa/examples/Paper/fig3.m | 144 ---- deconvolveCa/examples/Paper/fig4.m | 150 ---- deconvolveCa/examples/Paper/fig5.m | 191 ----- deconvolveCa/examples/Paper/fig6.m | 7 - .../examples/Paper/scripts/compute_rss_g.m | 65 -- .../Paper/scripts/fig2_demo_deconvolveAR1.m | 222 ------ .../examples/Paper/scripts/fig4_plot_trace.m | 16 - .../examples/Paper/scripts/show_results.m | 29 - deconvolveCa/examples/Paper/test_all.m | 5 - .../examples/ar1_constrained_foopsi.m | 74 -- deconvolveCa/examples/ar1_foopsi.m | 47 -- deconvolveCa/examples/ar1_mcmc.m | 27 - .../examples/ar1_thresholded_foopsi.m | 38 - deconvolveCa/examples/ar2_foopsi.m | 36 - deconvolveCa/examples/ar2_mcmc.m | 26 - .../examples/ar2_thresholded_foopsi.m | 54 -- deconvolveCa/examples/foopsi_kernel.m | 157 ---- deconvolveCa/examples/foopsi_onnls.m | 190 ----- deconvolveCa/examples/kernel_foopsi.m | 63 -- .../examples/kernel_thresholded_foopsi.m | 39 - deconvolveCa/examples/show_results.m | 39 - deconvolveCa/examples/test_all.m | 85 --- deconvolveCa/functions/GetSn.m | 50 -- deconvolveCa/functions/ar2exp.m | 13 - deconvolveCa/functions/choose_smin.m | 42 -- .../functions/constrained_foopsi_cvx.m | 56 -- .../functions/estimate_baseline_noise.m | 35 - deconvolveCa/functions/estimate_parameters.m | 44 -- .../functions/estimate_time_constant.m | 67 -- deconvolveCa/functions/exp2ar.m | 8 - deconvolveCa/functions/exp2kernel.m | 17 - deconvolveCa/functions/fit_gauss1.m | 83 --- deconvolveCa/functions/foopsi.m | 59 -- deconvolveCa/functions/gen_data.m | 62 -- deconvolveCa/functions/gen_sinusoidal_data.m | 63 -- deconvolveCa/functions/init_fig.m | 5 - deconvolveCa/functions/max_ht.m | 28 - deconvolveCa/oasis/choose_lambda.m | 41 -- deconvolveCa/oasis/constrained_oasisAR1.m | 250 ------- deconvolveCa/oasis/constrained_oasisAR2.m | 252 ------- deconvolveCa/oasis/create_kernel.m | 83 --- deconvolveCa/oasis/deconvCa.m | 356 --------- deconvolveCa/oasis/dsKernel.m | 42 -- deconvolveCa/oasis/foopsi_oasisAR1.m | 171 ----- deconvolveCa/oasis/foopsi_oasisAR2.m | 191 ----- deconvolveCa/oasis/oasisAR1.m | 109 --- deconvolveCa/oasis/oasisAR2.m | 156 ---- deconvolveCa/oasis/onnls.m | 214 ------ deconvolveCa/oasis/test_oasis.m | 34 - deconvolveCa/oasis/thresholded_nnls.m | 220 ------ deconvolveCa/oasis/thresholded_oasisAR1.m | 266 ------- deconvolveCa/oasis/thresholded_oasisAR2.m | 322 --------- deconvolveCa/oasis/update_g.m | 83 --- deconvolveCa/oasis/update_kernel_exp2.m | 131 ---- deconvolveCa/oasis/update_lam.m | 78 -- deconvolveCa/oasis/update_tau.m | 144 ---- deconvolveCa/oasis_kernel/choose_smin.m | 42 -- deconvolveCa/oasis_kernel/create_kernel.m | 83 --- deconvolveCa/oasis_kernel/deconvCa.m | 358 ---------- deconvolveCa/oasis_kernel/dsKernel.m | 42 -- deconvolveCa/oasis_kernel/test_oasis.m | 34 - .../oasis_kernel/update_kernel_exp2.m | 130 ---- deconvolveCa/setup.m | 36 - 97 files changed, 1 insertion(+), 10353 deletions(-) delete mode 100644 deconvolveCa/LICENSE delete mode 100644 deconvolveCa/MCMC/.gitignore delete mode 100644 deconvolveCa/MCMC/README.md delete mode 100644 deconvolveCa/MCMC/cont_ca_sampler.m delete mode 100644 deconvolveCa/MCMC/license.txt delete mode 100644 deconvolveCa/MCMC/plot_continuous_samples.m delete mode 100644 deconvolveCa/MCMC/sampling_demo_ar2.m delete mode 100644 deconvolveCa/MCMC/utilities/HMC_exact2.m delete mode 100644 deconvolveCa/MCMC/utilities/addSpike.m delete mode 100644 deconvolveCa/MCMC/utilities/get_initial_sample.m delete mode 100644 deconvolveCa/MCMC/utilities/get_next_spikes.m delete mode 100644 deconvolveCa/MCMC/utilities/lambda_rate.m delete mode 100644 deconvolveCa/MCMC/utilities/make_G_matrix.m delete mode 100644 deconvolveCa/MCMC/utilities/make_mean_sample.m delete mode 100644 deconvolveCa/MCMC/utilities/plot_marginals.m delete mode 100644 deconvolveCa/MCMC/utilities/removeSpike.m delete mode 100644 deconvolveCa/MCMC/utilities/replaceSpike.m delete mode 100644 deconvolveCa/MCMC/utilities/samples_cell2mat.m delete mode 100644 deconvolveCa/MCMC/utilities/tau_c2d.m delete mode 100644 deconvolveCa/MCMC/utilities/tau_d2c.m delete mode 100644 deconvolveCa/MCMC/wrapper.m delete mode 100644 deconvolveCa/README.md delete mode 100644 deconvolveCa/constrained-foopsi/.gitignore delete mode 100644 deconvolveCa/constrained-foopsi/MCEM_foopsi.m delete mode 100644 deconvolveCa/constrained-foopsi/README.md delete mode 100644 deconvolveCa/constrained-foopsi/acknowledgements.txt delete mode 100644 deconvolveCa/constrained-foopsi/constrained_foopsi.m delete mode 100644 deconvolveCa/constrained-foopsi/cvx_foopsi.m delete mode 100644 deconvolveCa/constrained-foopsi/lars_regression_noise.m delete mode 100644 deconvolveCa/constrained-foopsi/license.txt delete mode 100644 deconvolveCa/deconvolveCa.m delete mode 100644 deconvolveCa/examples/Paper/fig1.m delete mode 100644 deconvolveCa/examples/Paper/fig2.m delete mode 100644 deconvolveCa/examples/Paper/fig3.m delete mode 100644 deconvolveCa/examples/Paper/fig4.m delete mode 100644 deconvolveCa/examples/Paper/fig5.m delete mode 100644 deconvolveCa/examples/Paper/fig6.m delete mode 100644 deconvolveCa/examples/Paper/scripts/compute_rss_g.m delete mode 100644 deconvolveCa/examples/Paper/scripts/fig2_demo_deconvolveAR1.m delete mode 100644 deconvolveCa/examples/Paper/scripts/fig4_plot_trace.m delete mode 100644 deconvolveCa/examples/Paper/scripts/show_results.m delete mode 100644 deconvolveCa/examples/Paper/test_all.m delete mode 100644 deconvolveCa/examples/ar1_constrained_foopsi.m delete mode 100644 deconvolveCa/examples/ar1_foopsi.m delete mode 100644 deconvolveCa/examples/ar1_mcmc.m delete mode 100644 deconvolveCa/examples/ar1_thresholded_foopsi.m delete mode 100644 deconvolveCa/examples/ar2_foopsi.m delete mode 100644 deconvolveCa/examples/ar2_mcmc.m delete mode 100644 deconvolveCa/examples/ar2_thresholded_foopsi.m delete mode 100644 deconvolveCa/examples/foopsi_kernel.m delete mode 100644 deconvolveCa/examples/foopsi_onnls.m delete mode 100644 deconvolveCa/examples/kernel_foopsi.m delete mode 100644 deconvolveCa/examples/kernel_thresholded_foopsi.m delete mode 100644 deconvolveCa/examples/show_results.m delete mode 100644 deconvolveCa/examples/test_all.m delete mode 100644 deconvolveCa/functions/GetSn.m delete mode 100644 deconvolveCa/functions/ar2exp.m delete mode 100644 deconvolveCa/functions/choose_smin.m delete mode 100644 deconvolveCa/functions/constrained_foopsi_cvx.m delete mode 100644 deconvolveCa/functions/estimate_baseline_noise.m delete mode 100644 deconvolveCa/functions/estimate_parameters.m delete mode 100644 deconvolveCa/functions/estimate_time_constant.m delete mode 100644 deconvolveCa/functions/exp2ar.m delete mode 100644 deconvolveCa/functions/exp2kernel.m delete mode 100644 deconvolveCa/functions/fit_gauss1.m delete mode 100644 deconvolveCa/functions/foopsi.m delete mode 100644 deconvolveCa/functions/gen_data.m delete mode 100644 deconvolveCa/functions/gen_sinusoidal_data.m delete mode 100644 deconvolveCa/functions/init_fig.m delete mode 100644 deconvolveCa/functions/max_ht.m delete mode 100644 deconvolveCa/oasis/choose_lambda.m delete mode 100644 deconvolveCa/oasis/constrained_oasisAR1.m delete mode 100644 deconvolveCa/oasis/constrained_oasisAR2.m delete mode 100644 deconvolveCa/oasis/create_kernel.m delete mode 100644 deconvolveCa/oasis/deconvCa.m delete mode 100644 deconvolveCa/oasis/dsKernel.m delete mode 100644 deconvolveCa/oasis/foopsi_oasisAR1.m delete mode 100644 deconvolveCa/oasis/foopsi_oasisAR2.m delete mode 100644 deconvolveCa/oasis/oasisAR1.m delete mode 100644 deconvolveCa/oasis/oasisAR2.m delete mode 100644 deconvolveCa/oasis/onnls.m delete mode 100644 deconvolveCa/oasis/test_oasis.m delete mode 100644 deconvolveCa/oasis/thresholded_nnls.m delete mode 100644 deconvolveCa/oasis/thresholded_oasisAR1.m delete mode 100644 deconvolveCa/oasis/thresholded_oasisAR2.m delete mode 100644 deconvolveCa/oasis/update_g.m delete mode 100644 deconvolveCa/oasis/update_kernel_exp2.m delete mode 100644 deconvolveCa/oasis/update_lam.m delete mode 100644 deconvolveCa/oasis/update_tau.m delete mode 100644 deconvolveCa/oasis_kernel/choose_smin.m delete mode 100644 deconvolveCa/oasis_kernel/create_kernel.m delete mode 100644 deconvolveCa/oasis_kernel/deconvCa.m delete mode 100644 deconvolveCa/oasis_kernel/dsKernel.m delete mode 100644 deconvolveCa/oasis_kernel/test_oasis.m delete mode 100644 deconvolveCa/oasis_kernel/update_kernel_exp2.m delete mode 100644 deconvolveCa/setup.m diff --git a/OASIS_matlab b/OASIS_matlab index 5cafa3b..0a1251f 160000 --- a/OASIS_matlab +++ b/OASIS_matlab @@ -1 +1 @@ -Subproject commit 5cafa3b0d1fb9bb1a61b951d5a65db9ef3dd5767 +Subproject commit 0a1251f41b5999899d34a1a7fa5e04b5c7729972 diff --git a/deconvolveCa/LICENSE b/deconvolveCa/LICENSE deleted file mode 100644 index 9cecc1d..0000000 --- a/deconvolveCa/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/deconvolveCa/MCMC/.gitignore b/deconvolveCa/MCMC/.gitignore deleted file mode 100644 index 70d86e5..0000000 --- a/deconvolveCa/MCMC/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ - -*.m~ - -*.m~ diff --git a/deconvolveCa/MCMC/README.md b/deconvolveCa/MCMC/README.md deleted file mode 100644 index df9e158..0000000 --- a/deconvolveCa/MCMC/README.md +++ /dev/null @@ -1,47 +0,0 @@ -[![Join the chat at https://gitter.im/epnev/ca_source_extraction](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/epnev/ca_source_extraction?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -MCMC spike inference in continuous time -========================== - -The code takes as an input a time series vector of calcium observations -and produces samples from the posterior distribution of the underlying -spike in continuous time. The code also samples the model parameters -(baseline, spike amplitude, initial calcium concentration, firing rate, -noise variance) and also iteratively re-estimates the discrete time -constant of the model. More info can be found at - -Pnevmatikakis, E., Merel, J., Pakman, A. & Paninski, L. (2014). -Bayesian spike inference from calcium imaging data. Asilomar Conf. on -Signals, Systems, and Computers. http://arxiv.org/abs/1311.6864 - -For initializing the MCMC sampler, the algorithm uses the constrained deconvolution method maintained separately in https://github.com/epnev/constrained-foopsi - -### Contributors - -Eftychios A. Pnevmatikakis, Simons Foundation - -John Merel, Columbia University - -### Contact - -For questions join the chat room (see the button above) or open an issue (for bugs etc). - -### Acknowledgements - -Special thanks to Tim Machado for providing the demo dataset. - -License -======= - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . diff --git a/deconvolveCa/MCMC/cont_ca_sampler.m b/deconvolveCa/MCMC/cont_ca_sampler.m deleted file mode 100644 index fd21254..0000000 --- a/deconvolveCa/MCMC/cont_ca_sampler.m +++ /dev/null @@ -1,420 +0,0 @@ -function SAMPLES = cont_ca_sampler(Y,params) - -% MCMC continuous time sampler of spiketimes given a fluorescence trace Y - -% Inputs: -% Y data -% params parameters structure -% params.g discrete time constant(s) (estimated if not provided) -% params.sn initializer for noise (estimated if not provided) -% params.b initializer for baseline (estimated if not provided) -% params.c1 initializer for initial concentration (estimated if not provided) -% params.Nsamples number of samples after burn in (default 500) -% params.B number of burn in samples (default 200) -% params.marg flag for marginalized sampler for baseline and initial concentration (default 0) -% params.upd_gam flag for updating gamma (default 1) -% params.gam_step number of samples after which gamma is updated (default 50) -% params.std_move standard deviation of shifting kernel (default 3*Dt) -% params.add_move number of add moves per iteration (default T/100) -% params.init initial sample -% params.f imaging rate (default 1) -% params.p order of AR model (p == 1 or p == 2, default 1) -% params.defg default discrete time constants in case constrained_foopsi cannot find stable estimates -% params.TauStd standard deviation for time constants in continuous time (default [0.2,2]) -% params.A_lb lower bound for spike amplitude (default 0.1*range(Y)) -% params.b_lb lower bound for baseline (default 0.01 quantile of Y) -% params.c1_lb lower bound for initial value (default 0) - -% output struct SAMPLES -% ss Nsamples x 1 cells with spike times for each sample -% ns Nsamples x 1 vector with number of spikes -% Am Nsamples x 1 vector with samples for spike amplitude -% ld Nsamples x 1 vector with samples for firing rate - -% If marginalized sampler is used (params.marg = 1) -% Cb posterior mean and sd for baseline -% Cin posterior mean and sd for initial condition -% else -% Cb Nsamples x 1 vector with samples for baseline -% Cin Nsamples x 1 vector with samples for initial concentration -% sn Nsamples x 1 vector with samples for noise variance - -% If gamma is updated (params.upd_gam = 1) -% g Nsamples x p vector with the gamma updates - -% Author: Eftychios A. Pnevmatikakis and Josh Merel - -% Reference: Pnevmatikakis et al., Bayesian spike inference from calcium -% imaging data, Asilomar 2013. - -Y = Y(:); -T = length(Y); -isanY = ~isnan(Y); % Deal with possible missing entries -E = speye(T); -E = E(isanY,:); - -% define default parameters -defparams.g = []; % initializer for time constants -defparams.sn = []; % initializer for noise std -defparams.b = []; % initializer for baseline concentration -defparams.c1 = []; % initializer for initial concentration -defparams.c = []; % initializer for calcium concentration -defparams.sp = []; % initializer for spiking signal -defparams.bas_nonneg = 0; % allow negative baseline during initialization -defparams.Nsamples = 400; % number of samples after burn in period -defparams.B = 200; % length of burn in period -defparams.marg = 0; % flag to marginalize out baseline and initial concentration -defparams.upd_gam = 1; % flag for updating time constants -defparams.gam_step = 1; % flag for how often to update time constants -defparams.A_lb = 0.1*range(Y); % lower bound for spike amplitude -defparams.b_lb = quantile(Y,0.01); % lower bound for baseline -defparams.c1_lb = 0; % lower bound for initial concentration - -defparams.std_move = 3; % standard deviation of spike move kernel -defparams.add_move = ceil(T/100); % number of add moves -defparams.init = []; % sampler initializer -defparams.f = 1; % imaging rate (irrelevant) -defparams.p = 1; % order of AR process (use p = 1 or p = 2) -defparams.defg = [0.6,0.95]; % default time constant roots -defparams.TauStd = [.2,2]; % Standard deviation for time constant proposal -defparams.prec = 1e-2; % Precision parameter when adding new spikes -defparams.con_lam = true; % Flag for constant firing across time -defparams.print_flag = 0; - -if nargin < 2 - params = defparams; -else - if ~isfield(params,'g'); params.g = defparams.g; end - if ~isfield(params,'sn'); params.sn = defparams.sn; end - if ~isfield(params,'b'); params.b = defparams.b; end - if ~isfield(params,'c1'); params.c1 = defparams.c1; end - if ~isfield(params,'c'); params.c = defparams.c; end - if ~isfield(params,'sp'); params.sp = defparams.sp; end - if ~isfield(params,'bas_nonneg'); params.bas_nonneg = defparams.bas_nonneg; end - if ~isfield(params,'Nsamples'); params.Nsamples = defparams.Nsamples; end - if ~isfield(params,'B'); params.B = defparams.B; end - if ~isfield(params,'marg'); params.marg = defparams.marg; end - if ~isfield(params,'upd_gam'); params.upd_gam = defparams.upd_gam; end - if ~isfield(params,'gam_step'); params.gam_step = defparams.gam_step; end - if ~isfield(params,'std_move'); params.std_move = defparams.std_move; end - if ~isfield(params,'add_move'); params.add_move = defparams.add_move; end - if ~isfield(params,'init'); params.init = defparams.init; end - if ~isfield(params,'f'); params.f = defparams.f; end - if ~isfield(params,'p'); params.p = defparams.p; end - if ~isfield(params,'defg'); params.defg = defparams.defg; end - if ~isfield(params,'TauStd'); params.TauStd = defparams.TauStd; end - if ~isfield(params,'A_lb'); params.A_lb = defparams.A_lb; end - if ~isfield(params,'b_lb'); params.b_lb = defparams.b_lb; end - if ~isfield(params,'c1_lb'); params.c1_lb = defparams.c1_lb; end - if ~isfield(params,'prec'); params.prec = defparams.prec; end - if ~isfield(params,'con_lam'); params.con_lam = defparams.con_lam; end - if ~isfield(params,'print_flag'); params.print_flag = defparams.print_flag; end -end - -Dt = 1; % length of time bin - -marg_flag = params.marg; -gam_flag = params.upd_gam; -gam_step = params.gam_step; -std_move = params.std_move; -add_move = params.add_move; - -if isempty(params.init) - params.init = get_initial_sample(Y,params); -end -SAM = params.init; - -if isempty(params.g) - p = params.p; -else - p = length(params.g); % order of autoregressive process -end - -g = SAM.g(:)'; % check initial time constants, if not reasonable set to default values - -if g == 0 - gr = params.defg; - pl = poly(gr); - g = -pl(2:end); - p = 2; -end -gr = sort(roots([1,-g(:)'])); -if p == 1; gr = [0,max(gr)]; end -if any(gr<0) || any(~isreal(gr)) || length(gr)>2 || max(gr)>0.998 - gr = params.defg; -end -tau = -Dt./log(gr); -tau1_std = max(tau(1)/100,params.TauStd(1)); -tau2_std = min(tau(2)/5,params.TauStd(2)); -ge = max(gr).^(0:T-1)'; -if p == 1 - G1 = sparse(1:T,1:T,Inf*ones(T,1)); -elseif p == 2 - G1 = spdiags(ones(T,1)*[-min(gr),1],[-1:0],T,T); -else - error('This order of the AR process is currently not supported'); -end -G2 = spdiags(ones(T,1)*[-max(gr),1],[-1:0],T,T); - -sg = SAM.sg; - -spiketimes_ = SAM.spiketimes_; -lam_ = SAM.lam_; -A_ = SAM.A_*diff(gr); -b_ = max(SAM.b_,prctile(Y,8)); -C_in = max(min(SAM.C_in,Y(1)-b_),0); - -s_1 = zeros(T,1); -s_2 = zeros(T,1); -s_1(ceil(spiketimes_/Dt)) = exp((spiketimes_ - Dt*ceil(spiketimes_/Dt))/tau(1)); -s_2(ceil(spiketimes_/Dt)) = exp((spiketimes_ - Dt*ceil(spiketimes_/Dt))/tau(2)); - -prec = params.prec; - -ef_d = exp(-(0:T)/tau(2)); % construct transient exponentials -if p == 1 - h_max = 1; % max value of transient - ef_h = [0,0]; - e_support = find(ef_dT*Dt) = 2*T*Dt - spiketimes(spiketimes>T*Dt); - spiketimes_ = spiketimes; - trunc_spikes = ceil(spiketimes/Dt); - trunc_spikes(trunc_spikes == 0) = 1; - s_1 = zeros(T,1); - s_2 = zeros(T,1); - s_1(trunc_spikes) = exp((spiketimes_ - Dt*trunc_spikes)/tau(1)); - s_2(trunc_spikes) = exp((spiketimes_ - Dt*trunc_spikes)/tau(2)); - if p == 1; G1sp = zeros(T,1); else G1sp = G1\s_1(:); end - Gs = (-G1sp+G2\s_2(:))/diff(gr); - - %s_ = s_2 - s_1 - min(gr)*[0;s_2(1:end-1)] + max(gr)*[0;s_1(1:end-1)]; - %Gs = filter(1,[1,-sum(gr),prod(gr)]',s_/diff(gr)); - - ss{i} = spiketimes; - nsp = length(spiketimes); - ns(i) = nsp; - lam(i) = nsp/(T*Dt); - lam_ = lam(i); - - AM = [Gs,ones(T,1),ge]; - EAM = E*AM; - L = inv(Ld + EAM'*EAM/sg^2); - mu_post = (Ld + EAM'*EAM/sg^2)\(EAM'*Y(isanY)/sg^2 + Sp\mu); - if ~marg_flag - x_in = [A_;b_;C_in]; - if any(x_in <= lb) - x_in = max(x_in,(1+0.1*sign(lb)).*lb) + 1e-5; - end - if all(isnan(L(:))) % FN added to avoid error in R = chol(L) in HMC_exact2 due to L not being positive definite. It happens when isnan(det(Ld + AM'*AM/sg^2)), ie when Ld + AM'*AM/sg^2 is singular (not invertible). - Am(i) = NaN; - Cb(i) = NaN; - Cin(i) = NaN'; - else - [temp,~] = HMC_exact2(eye(3), -lb, L, mu_post, 1, Ns, x_in); - Am(i) = temp(1,Ns); - Cb(i) = temp(2,Ns); - Cin(i) = temp(3,Ns)'; - end - A_ = Am(i); - b_ = Cb(i); - C_in = Cin(i); - - Ym = Y - b_ - ge*C_in; - res = Ym - A_*Gs; - sg = 1./sqrt(gamrnd(1+length(isanY)/2,1/(0.1 + sum((res(isanY).^2)/2)))); - SG(i) = sg; - else - repeat = 1; - cnt = 0; - while repeat - A_ = mu_post(1) + sqrt(L(1,1))*randn; - repeat = (A_<0); - cnt = cnt + 1; - if cnt > 1e3 - error('The marginalized sampler cannot find a valid amplitude value. Set params.marg = 0 and try again.') - end - end - Am(i) = A_; - if i > B - mub = mub + mu_post(2:3); %mu_post(1+(1:p)); - Sigb = Sigb + L(2:3,2:3); %L(1+(1:p),1+(1:p)); - end - end - if gam_flag - if mod(i-B,gam_step) == 0 % update time constants - if p >= 2 % update rise time constant - logC = -norm(Y(isanY) - EAM*[A_;b_;C_in])^2; - tau_ = tau; - tau_temp = tau_(1)+(tau1_std*randn); - while tau_temp >tau(2) || tau_temptau_max || tau_temp - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/deconvolveCa/MCMC/plot_continuous_samples.m b/deconvolveCa/MCMC/plot_continuous_samples.m deleted file mode 100644 index 52a832a..0000000 --- a/deconvolveCa/MCMC/plot_continuous_samples.m +++ /dev/null @@ -1,143 +0,0 @@ -function plot_continuous_samples(SAMPLES,Y) - -% plot results of MCMC sampler -% The mean calcium sample, spike sampler raster plot and samples for -% amplitude, number of spikes, discrete time constants, noise variance, -% baseline and initial concentration are generated, together with their -% autocorrelation functions. If the marginalized flag was used, then the -% posterior pdfs of baseline and initial concentration are plotted. - -% Inputs: -% SAMPLES: structure with SAMPLES obtained from cont_ca_sampler.m -% Y: inpurt fluorescence trace - -% Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation - -T = length(Y); -N = length(SAMPLES.ns); -show_gamma = 1; -P = SAMPLES.params; -P.f = 1; -g = P.g(:); -p = min(length(g),2); -Dt = 1/P.f; % length of time bin -if ~isfield(SAMPLES,'g'); - show_gamma = 0; - SAMPLES.g = ones(N,1)*g'; -end - -if p == 1 - tau_1 = 0; - tau_2 = -Dt/log(g); % continuous time constant - G1 = speye(T); - G2 = spdiags(ones(T,1)*[-g,1],[-1:0],T,T); - ge = P.g.^((0:T-1)'); -elseif p == 2 - gr = roots([1,-g']); - p1_continuous = log(min(gr))/Dt; - p2_continuous = log(max(gr))/Dt; - tau_1 = -1/p1_continuous; %tau h - smaller (tau_d * tau_r)/(tau_d + tau_r) - tau_2 = -1/p2_continuous; %tau decay - larger - G1 = spdiags(ones(T,1)*[-min(gr),1],[-1:0],T,T); - G2 = spdiags(ones(T,1)*[-max(gr),1],[-1:0],T,T); - ge = G2\[1;zeros(T-1,1)]; -else - error('This order of the AR process is currently not supported'); -end - - -if length(SAMPLES.Cb) == 2 - marg = 1; % marginalized sampler -else - marg = 0; % full sampler -end - -C_rec = zeros(N,T); -for rep = 1:N - %trunc_spikes = ceil(SAMPLES.ss{rep}/Dt); - tau = SAMPLES.g(rep,:); - gr = exp(-1./tau); - ge = max(gr).^(0:T-1)'; - s_1 = sparse(ceil(SAMPLES.ss{rep}/Dt),1,exp((SAMPLES.ss{rep} - Dt*ceil(SAMPLES.ss{rep}/Dt))/tau(1)),T,1); - s_2 = sparse(ceil(SAMPLES.ss{rep}/Dt),1,exp((SAMPLES.ss{rep} - Dt*ceil(SAMPLES.ss{rep}/Dt))/tau(2)),T,1); - if gr(1) == 0 - G1 = sparse(1:T,1:T,Inf*ones(T,1)); G1sp = zeros(T,1); - else - G1 = spdiags(ones(T,1)*[-min(gr),1],[-1:0],T,T); G1sp = G1\s_1(:); - end - G2 = spdiags(ones(T,1)*[-max(gr),1],[-1:0],T,T); - Gs = (-G1sp+ G2\s_2(:))/diff(gr); - if marg - %C_rec(rep,:) = SAMPLES.Cb(1) + SAMPLES.Am(rep)*filter(1,[1,-SAMPLES.g(rep,:)],full(s_)+[SAMPLES.Cin(:,1)',zeros(1,T-p)]); - C_rec(rep,:) = SAMPLES.Cb(1) + SAMPLES.Am(rep)*Gs + (ge*SAMPLES.Cin(:,1)); - else - %C_rec(rep,:) = SAMPLES.Cb(rep) + SAMPLES.Am(rep)*filter(1,[1,-SAMPLES.g(rep,:)],full(s_)+[SAMPLES.Cin(rep,:),zeros(1,T-p)]); - C_rec(rep,:) = SAMPLES.Cb(rep) + SAMPLES.Am(rep)*Gs + (ge*SAMPLES.Cin(rep,:)'); - end -end -Nc = 60; - -if marg - rows = 4; -else - rows = 5; -end - -figure; - set(gcf, 'PaperUnits', 'inches','Units', 'inches') - set(gcf, 'PaperPositionMode', 'manual') - set(gcf, 'PaperPosition',[0,0, 14, 15]) - set(gcf, 'Position',[2,2, 14, 15]) - ha(1) = subplot(rows,4,[1:4]);plot(Dt*(1:T),Y); hold all; plot(Dt*(1:T),mean(C_rec,1),'linewidth',2); - title('Calcium traces','fontweight','bold','fontsize',14) - legend('Raw data','Mean sample'); - ha(2) = subplot(rows,4,[5:8]); imagesc((1:T)*Dt,1:N,samples_cell2mat(SAMPLES.ss,T)); - title('Spike raster plot','fontweight','bold','fontsize',14) - linkaxes(ha,'x'); - subplot(rows,4,4+5); plot(1:N,SAMPLES.ns); title('# of spikes','fontweight','bold','fontsize',14) - subplot(rows,4,4+6); plot(-Nc:Nc,xcov(SAMPLES.ns,Nc,'coeff')); set(gca,'XLim',[-Nc,Nc]); - title('Autocorrelation','fontweight','bold','fontsize',14) - - if ~show_gamma - subplot(rows,4,4+7); plot(1:N,SAMPLES.ld); title('Firing Rate','fontweight','bold','fontsize',14) - subplot(rows,4,4+8); plot(-Nc:Nc,xcov(SAMPLES.ld,Nc,'coeff')); set(gca,'XLim',[-Nc,Nc]) - title('Autocorrelation','fontweight','bold','fontsize',14) - else - if gr(1) == 0 - subplot(rows,4,4+7); plot(1:N,exp(-1./SAMPLES.g(:,2))); title('Decay Time Constant','fontweight','bold','fontsize',14); - subplot(rows,4,4+8); plot(-Nc:Nc,xcov(exp(-1./SAMPLES.g(:,2)),Nc,'coeff')); title('Autocorrelation','fontweight','bold','fontsize',14); - set(gca,'XLim',[-Nc,Nc]) - else - subplot(rows,4,4+7); plot(1:N,exp(-1./SAMPLES.g)); title('Decay Time Constants','fontweight','bold','fontsize',14); - g_cov = xcov(exp(-1./SAMPLES.g),Nc,'coeff'); - subplot(rows,4,4+8); plot(-Nc:Nc,g_cov(:,[1,4])); title('Autocorrelation','fontweight','bold','fontsize',14); - set(gca,'XLim',[-Nc,Nc]) - end - end - - subplot(rows,4,4+9); plot(1:N,SAMPLES.Am); title('Spike Amplitude','fontweight','bold','fontsize',14) - subplot(rows,4,4+10); plot(-Nc:Nc,xcov(SAMPLES.Am,Nc,'coeff')); set(gca,'XLim',[-Nc,Nc]) - title('Autocorrelation','fontweight','bold','fontsize',14) - if marg - xx = SAMPLES.Cb(1) + linspace(-4*SAMPLES.Cb(2),4*SAMPLES.Cb(2)); - subplot(4,4,15); plot(xx,normpdf(xx,SAMPLES.Cb(1),SAMPLES.Cb(2))); - set(gca,'XLim',[xx(1),xx(end)]) - title('Marg. post. of baseline','fontweight','bold','fontsize',14) - - xx = SAMPLES.Cin(1) + linspace(-4*SAMPLES.Cin(2),4*SAMPLES.Cin(2)); - subplot(4,4,16); plot(xx,normpdf(xx,SAMPLES.Cin(1),SAMPLES.Cin(2))); - set(gca,'XLim',[xx(1),xx(end)]) - title('Marg. post. of initial con','fontweight','bold','fontsize',14) - else - subplot(5,4,4+11); plot(1:N,SAMPLES.Cb); title('Baseline','fontweight','bold','fontsize',14) - subplot(5,4,4+12); plot(-Nc:Nc,xcov(SAMPLES.Cb,Nc,'coeff')); set(gca,'XLim',[-Nc,Nc]) - title('Autocorrelation','fontweight','bold','fontsize',14) - subplot(5,4,4+13); plot(1:N,SAMPLES.Cin); title('Initial Concentration','fontweight','bold','fontsize',14) - xcov_Cin = xcov(SAMPLES.Cin,Nc,'coeff'); - subplot(5,4,4+14); plot(-Nc:Nc,xcov_Cin); set(gca,'XLim',[-Nc,Nc]) - title('Autocorrelation','fontweight','bold','fontsize',14) - subplot(5,4,4+15); plot(1:N,SAMPLES.sn2); title('Noise variance','fontweight','bold','fontsize',14) - subplot(5,4,4+16); plot(-Nc:Nc,xcov(SAMPLES.sn2,Nc,'coeff')); set(gca,'XLim',[-Nc,Nc]) - title('Autocorrelation','fontweight','bold','fontsize',14) - end - drawnow; \ No newline at end of file diff --git a/deconvolveCa/MCMC/sampling_demo_ar2.m b/deconvolveCa/MCMC/sampling_demo_ar2.m deleted file mode 100644 index 43c885e..0000000 --- a/deconvolveCa/MCMC/sampling_demo_ar2.m +++ /dev/null @@ -1,64 +0,0 @@ -% creating a demo for the MCMC sampler - -clearvars; -addpath utilities -dt = 1e-1; % Data is generated with provided dt but sampled with Dt = 1 -T = 7000; -ld = 0.05; % rate spikes per second - -s = rand(1,round(T/dt)) < ld*dt; -tau_rise = 2; -tau_decay = 10; -hmax = tau_decay/(tau_decay+tau_rise)*(tau_rise/(tau_decay+tau_rise))^(tau_rise/tau_decay); -[g,h1] = tau_c2d(tau_rise,tau_decay,dt); - -b = hmax/4; % baseline value -cin = [.2*b,.15*b]; % initial concentration -c = [cin,filter(h1,[1,-g],s(3:end),filtic(h1,[1,-g],cin))] + b; % true calcium at original resolution -c_true = c(round(1/dt):round(1/dt):round(T/dt)); % true calcium at sampled resolution -sg = hmax/4; % noise level -y = c_true + sg*randn(1,length(c_true)); % noisy observations - -figure;subplot(2,1,1); plot(dt:dt:T,c); hold all; scatter(1:T,y,'r*'); - legend('True Calcium','Observed Values'); - -%% Run constrained deconvolution approach (constrained foopsi) - -[g2,h2] = tau_c2d(tau_rise,tau_decay,1); % generate discrete time constants - -[ca_foopsi,cb,c1,~,~,spikes_foopsi] = constrained_foopsi(y,[],[],g2); - -% do some plotting -spiketimes{1} = find(s)*dt; -spikeRaster = samples_cell2mat(spiketimes,T,1); -f = find(spikeRaster); -spikes = zeros(sum(spikeRaster),2); -count = 0; -for cnt = 1:length(f) - spikes(count+(1:spikeRaster(f(cnt))),1) = f(cnt); - spikes(count+(1:spikeRaster(f(cnt))),2) = 0.95 + 0.025*max(spikes_foopsi)*(1:spikeRaster(f(cnt))); - count = count + spikeRaster(f(cnt)); -end - -subplot(2,1,2); -stem(spikes_foopsi); hold all; - scatter(spikes(:,1),spikes(:,2)-0.95+max(spikes_foopsi),15,'magenta','filled'); - axis([1,T,0,max(spikes(:,2))-0.95+max(spikes_foopsi)]); - title('Foopsi Spikes','FontWeight','bold','Fontsize',14); xlabel('Timestep','FontWeight','bold','Fontsize',16); - legend('Foopsi Spikes','Ground Truth'); - drawnow; - -%% run continuous time MCMC sampler - -params.p = 2; -params.g = g2; -params.sp = spikes_foopsi; % pass results of foopsi for initialization (if not, they are computed) -params.c = ca_foopsi; -params.b = cb; -params.c1 = c1; -params.sn = sg; -params.marg = 0; - -SAMPLES = cont_ca_sampler(y,params); %% MCMC -plot_continuous_samples(SAMPLES,y(:)); -M = plot_marginals(SAMPLES.ss,T,spikeRaster); \ No newline at end of file diff --git a/deconvolveCa/MCMC/utilities/HMC_exact2.m b/deconvolveCa/MCMC/utilities/HMC_exact2.m deleted file mode 100644 index a3b53ab..0000000 --- a/deconvolveCa/MCMC/utilities/HMC_exact2.m +++ /dev/null @@ -1,229 +0,0 @@ -function [Xs, bounce_count] = HMC_exact2(F, g, M, mu_r, cov, L, initial_X) - -% Author: Ari Pakman - -% returns samples from a d-dimensional Gaussian with m constraints given by F*X+g >0 -% If cov == true -% then M is the covariance and the mean is mu = mu_r -% if cov== false -% then M is the precision matrix and the log-density is -1/2 X'*M*X + r'*X - -% Input -% F: m x d matrix -% g: m x 1 vector -% M d x d matrix, must be symmmetric and definite positive -% mu_r d x 1 vector. -% cov: see explanation above -% L: number of samples desired -% initial_X d x 1 vector. Must satisfy the constraint. - - -% Output -% Xs: d x L matrix, each column is a sample -% bounce_count: number of times the particle bounced - -%% go to a whitened frame - -m = size(g,1); -if size(F,1) ~= m - display('error'); - return -end - - -if cov - mu= mu_r; - g = g + F*mu; - %if min(eig(M))<0 - % M = M - 1.01*min(eig(M))*eye(size(M,1)); - %end - R = chol(M); - F = F*R'; - initial_X= initial_X -mu; - initial_X = R'\initial_X; - -else - r=mu_r; - R=chol(M); % M = R'*R - mu = R\(R'\r); - g = g+F*mu; - F = F/R; % this is the time-consuming step in this code section - initial_X= initial_X -mu; - initial_X = R*initial_X; -end - - - - - -d = size(initial_X,1); - - -Xs=NaN; - -bounce_count =0; - -nearzero= 10000*eps; - - - - -% Verify that initial_X is feasible - c= F*initial_X +g; - if any(c<0) - display('error: inconsistent initial condition'); - return - end - - - -% Unsparcify the linear constraints -g=full(g); -F2 = sum(F.*F,2); % squared norm of the rows of F, needed for reflecting the velocity -F=full(F); % if we don't unsparcify qj= F(j,:)*V/F2(j) becomes very slow. -Ft = F'; - - -%% Sampling loop - - -last_X= initial_X; -Xs=zeros(d,L); -Xs(:,1)=initial_X; - -i=2; -while (i <= L) -%i -stop=0; -j=0; -V0= normrnd(0,1, d,1); % initial velocity -X = last_X; - -T=pi/2; % total time the particle will move -tt=0; % records how much time the particle already moved - - while (1) - a = V0; - a= real(a); - b = X; - - fa = F*a; - fb = F*b; - - U = sqrt(fa.^2 + fb.^2); - phi = atan2(-fa,fb); % -pi < phi < +pi - - - - pn = abs(g./U)<=1; % these are the walls that may be hit - - - % find the first time constraint becomes zero - - if any(pn) - inds = find(pn); - - phn= phi(pn); - - t1=-phn + acos(-g(pn)./U(pn)); % time at which coordinates hit the walls - % t1 in [-pi, 2*pi] - t1(t1<0) = 2*pi + t1(t1<0); % t1 in [0, 2*pi] - t2 = -t1 -2*phn; % second solution to hit the walls - % t2 in [-4*pi, 2*pi] - t2(t2<0) = 2*pi + t2(t2<0); % t2 in [-2*pi, 2*pi] - t2(t2<0) = 2*pi + t2(t2<0); % t2 in [0, 2*pi] - - - % if there was a previous reflection (j>0) - % and there is a potential reflection at the sample plane - % make sure that a new reflection at j is not found because of numerical error - if j>0 - if pn(j)==1 - indj=sum(pn(1:j)); - tt1 = t1(indj); - if abs(tt1) < nearzero || abs(tt1-2*pi)< nearzero - t1(indj)=Inf; - else - tt2 = t2(indj); - if abs(tt2) < nearzero || abs(tt1-2*pi)< nearzero - t2(indj) = Inf; - end - end - end - end - - - [mt1 ind1] = min(t1); - [mt2 ind2] = min(t2); - - [mt ind12] = min([mt1 mt2]); - - if ind12==1 - m_ind = ind1; - else - m_ind= ind2; - end - - % find the reflection plane - j = inds(m_ind); % j is an index in the full vector of dim-m, not in the restriced vector determined by pn. - - else %if pn(i) =0 for all i - mt =T; - end %if pn(i) - - tt=tt+mt; -% fprintf(num2str(tt/T)); - - if tt>=T - mt= mt-(tt-T); - stop=1; - - end - - % move the particle a time mt - - X = a*sin(mt) + b*cos(mt); - V = a*cos(mt) - b*sin(mt); - - if stop - break; - end - - % compute reflected velocity - - qj= F(j,:)*V/F2(j); - V0 = V -2*qj*Ft(:,j); - bounce_count = bounce_count+ 1; - - % dif =V0'*M*V0 - V'*M*V; - - end % while(1) - - % at this point we have a sampled value X, but due to possible - % numerical instabilities we check that the candidate X satisfies the - % constraints before accepting it. - - if all(F*X +g > 0) - Xs(:,i)=X; - last_X = X; - i= i+1; - - else - disp('hmc reject') - - end - -end %while (i <= L) - -% transform back to the unwhitened frame -if cov - Xs = R'*Xs + repmat(mu, 1,L); -else - Xs = R\Xs + repmat(mu, 1,L); -end - - - - -end - diff --git a/deconvolveCa/MCMC/utilities/addSpike.m b/deconvolveCa/MCMC/utilities/addSpike.m deleted file mode 100644 index 05e2195..0000000 --- a/deconvolveCa/MCMC/utilities/addSpike.m +++ /dev/null @@ -1,65 +0,0 @@ -function [newSpikeTrain, newCalcium, newLL] = addSpike(oldSpikeTrain,oldCalcium,oldLL,filters,tau,obsCalcium,timeToAdd,indx,Dt,A) - -% Add a given spike to the existing spike train. - -% Inputs: -% oldSpikeTrain: current spike train -% oldCalcium: current noiseless calcium trace -% oldLL: current value of the log-likelihood function -% filters: exponential rise and decay kernels for calcium transient -% tau: continuous time rise and decay time constants -% obsCalcium: observed fluorescence trace -% timetoAdd: time of the spike to be added -% indx: place where the new spike is added in the existing spike train vector -% Dt: time-bin width -% A: spike amplitude - -% Outputs: -% newSpikeTrain: new vector of spike times -% newCalcium: new noiseless calcium trace -% newLL: new value of the log-likelihood function - -% Author: Eftychios A. Pnevmatikakis and Josh Merel - - tau_h = tau(1); - tau_d = tau(2); - - ef_h = filters{1,1}; - ef_d = filters{1,2}; - ef_nh = filters{2,1}; - ef_nd = filters{2,2}; - - if isempty(oldSpikeTrain); indx = 1; end - newSpikeTrain = [oldSpikeTrain(1:indx-1) timeToAdd oldSpikeTrain(indx:end)]; %possibly inefficient, change if problematic (only likely to be a problem for large numbers of spikes) - - %use infinite precision to scale the precomputed FIR approximation to the calcium transient - wk_h = A*exp((timeToAdd - Dt*ceil(timeToAdd/Dt))/tau_h); - wk_d = A*exp((timeToAdd - Dt*ceil(timeToAdd/Dt))/tau_d); - - %%%%%%%%%%%%%%%%% - %handle ef_h first - newCalcium = oldCalcium; - tmp = 1 + (floor(timeToAdd):min((length(ef_h)+floor(timeToAdd)-1),length(newCalcium)-1)); - wef_h = wk_h*ef_h(1:length(tmp)); - newCalcium(tmp) = newCalcium(tmp) + wef_h; - - %if you really want to, ef*ef' could be precomputed and passed in - relevantResidual = obsCalcium(tmp)-oldCalcium(tmp); - relevantResidual(isnan(relevantResidual)) = 0; - %newLL = oldLL - ( wk_h^2*norm(ef_h(1:length(tmp)))^2 - 2*relevantResidual*(wk_h*ef_h(1:length(tmp))')); - newLL = oldLL - ( wk_h^2*ef_nh(length(tmp)) - 2*relevantResidual*wef_h(:)); - oldCalcium = newCalcium; - oldLL = newLL; - %%%%%%%%%%%%%%%%% - - %%%%%%%%%%%%%%%%% - %handle ef_d next - tmp = 1 + (floor(timeToAdd):min((length(ef_d)+floor(timeToAdd)-1),length(newCalcium)-1)); - wef_d = wk_d*ef_d(1:length(tmp)); - newCalcium(tmp) = newCalcium(tmp) + wef_d; - - relevantResidual = obsCalcium(tmp)-oldCalcium(tmp); - relevantResidual(isnan(relevantResidual)) = 0; - %newLL = oldLL - ( wk_d^2*norm(ef_d(1:length(tmp)))^2 - 2*relevantResidual*(wk_d*ef_d(1:length(tmp))')); - newLL = oldLL - ( wk_d^2*ef_nd(length(tmp)) - 2*relevantResidual*wef_d(:)); - %%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/deconvolveCa/MCMC/utilities/get_initial_sample.m b/deconvolveCa/MCMC/utilities/get_initial_sample.m deleted file mode 100644 index 774a6f4..0000000 --- a/deconvolveCa/MCMC/utilities/get_initial_sample.m +++ /dev/null @@ -1,51 +0,0 @@ -function SAM = get_initial_sample(Y,params) - -% obtain initial sample by performing sparse noise-constrained deconvolution - -% Inputs: -% Y: observed fluorescence trace -% params: parameter struct (results of constrained foopsi can be passed here to avoid unnecessary computation) - -% Output: -% SAM: sample structure with values for spikes in continuous time, -% amplitude, baseline, noise, initial concentration and time constants - -% Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation - - -if isfield(params,'p'); options.p = params.p; else options.p = 1; end -if isempty(params.c) || isempty(params.b) || isempty(params.c1) || isempty(params.g) || isempty(params.sn) || isempty(params.sp) - fprintf('Initializing using noise constrained FOOPSI... '); - options.bas_nonneg = params.bas_nonneg; - [c,b,c1,g,sn,sp] = constrained_foopsi(Y,params.b,params.c1,params.g,params.sn,options); - fprintf('done. \n'); -else - c = params.c; - b = params.b; - c1 = params.c1; - g = params.g; - sn = params.sn; - sp = params.sp; -end - -Dt = 1; -T = length(Y); -if ~exist('sp','var') - G = make_G_matrix(T,params.g); - sp = G*c; -end -s_in = sp>0.15*max(sp); -spiketimes_ = Dt*(find(s_in) + rand(size(find(s_in))) - 0.5); -spiketimes_(spiketimes_ >= T*Dt) = 2*T*Dt - spiketimes_(spiketimes_ >= T*Dt); -SAM.lam_ = length(spiketimes_)/(T*Dt); -SAM.spiketimes_ = spiketimes_; - -SAM.A_ = max(median(sp(s_in)),max(sp(s_in))/4); % initial amplitude value -if length(g) == 2 - SAM.A_ = SAM.A_/sqrt(g(1)^2+4*g(2)); -end - -SAM.b_ = max(b,min(Y)+range(Y)/25); % initial baseline value -SAM.C_in = max(c1,(Y(1)-b)/10); % initial value sample -SAM.sg = sn; % initial noise value -SAM.g = g; % initial time constant value \ No newline at end of file diff --git a/deconvolveCa/MCMC/utilities/get_next_spikes.m b/deconvolveCa/MCMC/utilities/get_next_spikes.m deleted file mode 100644 index 35e2a22..0000000 --- a/deconvolveCa/MCMC/utilities/get_next_spikes.m +++ /dev/null @@ -1,159 +0,0 @@ -function [new_spikes, new_calcium, moves] = get_next_spikes(curr_spikes,curr_calcium,calciumSignal,filters,tau,calciumNoiseVar, lam, proposalSTD, add_move, Dt, A, con_lam) - -% Function for sampling the next of spike times given the current set of spike time and observed fluorescence trace - -% Inputs: -% curr_spikes: current set of spike times in continuous time -% curr_calcium: current estimate of noiseless calcium trace -% calciumSingal: observed fluorescence trace -% filters: exponential rise and decay kernels for calcium transient -% tau: continuous time rise and decay time constants -% calciumNoiseVar: observation noise variance -% lam: function handle for computing firing rate -% proposalSTD: standard deviation for perturbing a spike time -% add_move: # of addition/removal proposals per sample -% Dt: time-bin width -% A: spike amplitude -% con_lam: flag for constant firing rate (speeds up computation) - -% Outputs: -% new_spikes: new set of spike times -% new_calcium: new estimate of noiseless calcium trace -% moves: acceptance probabilities for perturbing,adding, droping spikes respectively - -% Author: Eftychios A. Pnevmatikakis and Josh Merel - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - %% initialize some parameters - T = length(calciumSignal); %for all of this, units are bins and spiketrains go from 0 to T where T is number of bins - ff = ~isnan(calciumSignal); % entries with data - - %% start with initial spiketrain and initial predicted calcium - si = curr_spikes; %initial set of spike times has no spikes - this will not be sorted but that shouldn't be a problem - new_calcium = curr_calcium; %initial calcium is set to baseline - - N = length(si); %number of spikes in spiketrain - - %initial logC - compute likelihood initially completely - updates to likelihood will be local - logC = -norm(new_calcium(ff)-calciumSignal(ff))^2; - - %flag for uniform vs likelihood proposal (if using likelihood proposal, then time shifts are pure Gibbs) - %this really should be split into four cases (not implemented yet), - % 1) RW for time shifts with uniform add/drop - % 2) RW for time shifts with likelihood proposal add/drop - % 3) Gibbs for time shifts with uniform add/drop - % 4) Gibbs for time shifts with likelihood proposal add/drop - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - addMoves = [0 0]; %first elem is number successful, second is number total - dropMoves = [0 0]; - timeMoves = [0 0]; - - %% loop over spikes, perform spike time move (could parallelize here for non-interacting spikes, i.e. spikes that are far enough away) - - for ni = 1:N %possibly go through in a random order (if you like) - - tmpi = si(ni); - tmpi_ = si(ni)+(proposalSTD*randn); %with bouncing off edges - if tmpi_<0 - tmpi_ = -(tmpi_); - elseif tmpi_>T - tmpi_ = T-(tmpi_-T); - end - - %set si_ to set of spikes with the move and ci_ to adjusted calcium and update logC_ to adjusted -% [si_, ci_, logC_] = removeSpike(si,ci,logC,ef,tau,calciumSignal,tmpi,ni,Dt,A); -% [si_, ci_, logC_] = addSpike(si_,ci_,logC_,ef,tau,calciumSignal,tmpi_,ni,Dt,A); - [si_, ci_, logC_] = replaceSpike(si,new_calcium,logC,filters,tau,calciumSignal,tmpi,ni,tmpi_,Dt,A); - - %accept or reject - ratio = exp((logC_-logC)/(2*calciumNoiseVar)); - if ~con_lam; ratio = ratio*lam(tmpi)/lam(tmpi_); end - if ratio>1 %accept - si = si_; - new_calcium = ci_; - logC = logC_; - timeMoves = timeMoves + [1 1]; - elseif rand1 %accept - si = si_; - new_calcium = ci_; - logC = logC_; - addMoves = addMoves + [1 1]; - elseif rand0 - %propose a uniform removal - tmpi = randi(N); - [si_, ci_, logC_] = removeSpike(si,new_calcium,logC,filters,tau,calciumSignal,si(tmpi),tmpi,Dt,A); - - %reverse probability - rprob = 1/(T*Dt); - - %compute forward prob - fprob = 1/N; - - %accept or reject - ratio = exp((logC_ - logC)/(2*calciumNoiseVar))*(rprob/fprob)*(1/lam(si(tmpi))); %posterior times reverse prob/forward prob - - if ratio>1 %accept - si = si_; - new_calcium = ci_; - logC = logC_; - dropMoves = dropMoves + [1 1]; - elseif rand floor(timetoAdd) - wef_h = wk_hr*[zeros(1,min(length(tmp),floor(timetoRemove)-floor(timetoAdd))),ef_h(1:length(tmp)-(floor(timetoRemove)-floor(timetoAdd)))] - wk_ha*ef_h(1:length(tmp)); - else - wef_h = wk_hr*ef_h(1:length(tmp)) - wk_ha*[zeros(1,min(length(tmp),floor(timetoAdd)-floor(timetoRemove))),ef_h(1:length(tmp)-(floor(timetoAdd)-floor(timetoRemove)))]; - end - newCalcium(tmp) = newCalcium(tmp) - wef_h; - end - - %%%%%%%%%%%%%%%%% - %handle ef_d next - tmp = 1+ (min_t:min((length(ef_d)+min_t-1),length(newCalcium)-1)); - if floor(timetoRemove) == floor(timetoAdd) - wef_d = (wk_dr-wk_da)*ef_d(1:length(tmp)); - elseif floor(timetoRemove) > floor(timetoAdd) - wef_d = wk_dr*[zeros(1,min(length(tmp),floor(timetoRemove)-floor(timetoAdd))),ef_d(1:length(tmp)-(floor(timetoRemove)-floor(timetoAdd)))] - wk_da*ef_d(1:length(tmp)); - else - wef_d = wk_dr*ef_d(1:length(tmp)) - wk_da*[zeros(1,min(length(tmp),floor(timetoAdd)-floor(timetoRemove))),ef_d(1:length(tmp)-(floor(timetoAdd)-floor(timetoRemove)))]; - end - newCalcium(tmp) = newCalcium(tmp) - wef_d; - - obstemp = obsCalcium(tmp); - newLL = oldLL - norm(newCalcium(tmp)-obstemp)^2 + norm(oldCalcium(tmp)-obstemp)^2; %+ 2*(newCalcium(tmp)-oldCalcium - %%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/deconvolveCa/MCMC/utilities/samples_cell2mat.m b/deconvolveCa/MCMC/utilities/samples_cell2mat.m deleted file mode 100644 index afd442c..0000000 --- a/deconvolveCa/MCMC/utilities/samples_cell2mat.m +++ /dev/null @@ -1,24 +0,0 @@ -function spikeRaster = samples_cell2mat(sampleCell,T,Dt) - -% Constructs matrix of spike raster plot from cell array of spike times - -% Inputs: -% sampleCell: Cell array with spike times in continuous time (SAMPLES.ss) -% T: End time of trace/experiment -% Dt: Time-bin resolution (default: 1) - -% Output: -% spikeRaster: Spike raster plot matrix - -% Author: Eftychios A. Pnevmatikakis and Josh Merel - -if nargin == 2 - Dt = 1; -end -bins = 0:Dt:(T-Dt); -nsamples = length(sampleCell); -spikeRaster = zeros(nsamples,length(bins)); -for i = 1:nsamples - tmp = histc([sampleCell{i}(:); inf],[bins, (T+1)]); - spikeRaster(i,:) = tmp(1:(end-1))'; -end \ No newline at end of file diff --git a/deconvolveCa/MCMC/utilities/tau_c2d.m b/deconvolveCa/MCMC/utilities/tau_c2d.m deleted file mode 100644 index 7815606..0000000 --- a/deconvolveCa/MCMC/utilities/tau_c2d.m +++ /dev/null @@ -1,15 +0,0 @@ -function [g,h1] = tau_c2d(tau_r,tau_d,dt) - -% convert continuous time constants to discrete with resolution dt -% h(t) = (1-exp(-t/tau_r))*exp(-t/tau_d) -% g: discrete time constants -% h1: h(dt); -% h*s can be written in discrete form as filter(h1,[1,-g],s) - -% Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation - -A = [-(2/tau_d+1/tau_r), - (tau_r+tau_d)/(tau_r*tau_d^2); 1 0]; -lc = eig(A*dt); -ld = exp(lc); -g = [sum(ld),-prod(ld)]; -h1 = (1-exp(-dt/tau_r))*exp(-dt/tau_d); \ No newline at end of file diff --git a/deconvolveCa/MCMC/utilities/tau_d2c.m b/deconvolveCa/MCMC/utilities/tau_d2c.m deleted file mode 100644 index f29514c..0000000 --- a/deconvolveCa/MCMC/utilities/tau_d2c.m +++ /dev/null @@ -1,15 +0,0 @@ -function tau = tau_d2c(g,dt) - -% convert discrete time constantswith resolution dt to continuous -% h(t) = (1-exp(-t/tau(1)))*exp(-t/tau(2)) - -% Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation - -gr = max(roots([1,-g(:)']),0); -p1_continuous = log(min(gr))/dt; -p2_continuous = log(max(gr))/dt; -tau_1 = -1/p1_continuous; %tau h - smaller (tau_d * tau_r)/(tau_d + tau_r) -tau_2 = -1/p2_continuous; %tau decay - larger - -tau_rise = 1/(1/tau_1 - 1/tau_2); -tau = [tau_rise,tau_2]; %tau_h , tau_d \ No newline at end of file diff --git a/deconvolveCa/MCMC/wrapper.m b/deconvolveCa/MCMC/wrapper.m deleted file mode 100644 index 9c680d7..0000000 --- a/deconvolveCa/MCMC/wrapper.m +++ /dev/null @@ -1,13 +0,0 @@ -clear; -load traceData.mat; -addpath utilities -addpath(genpath('../constrained-foopsi')); -%Y = squeeze(traceData.traces(129,7,:)); % pick a particular trace (low SNR) -Y = mean(squeeze(traceData.traces(:,7,:))); % average over ROI (high SNR) - -%% run MCMC sampler and plot results -params.p = 1; -params.print_flag = 1; -params.B = 300; -SAMP = cont_ca_sampler(Y,params); -plot_continuous_samples(SAMP,Y); \ No newline at end of file diff --git a/deconvolveCa/README.md b/deconvolveCa/README.md deleted file mode 100644 index d315134..0000000 --- a/deconvolveCa/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# OASIS: Fast online deconvolution of calcium imaging data - -Code accompanying the paper "Fast Active Set Method for Online Spike Inference from Calcium Imaging". [arXiv, 2016] - -Python: https://github.com/j-friedrich/OASIS - -MATLAB: https://github.com/zhoupc/OASIS_matlab - -### Use OASIS - -The implementation of OASIS requires several functions for different formulation of the optimization problems. They can be found within the folder `OASIS_matlab/oasis/`. However, we highly recommend you use the wrapper function `deconvolveCa.m` to run differnet algorithms with one command. - -| | AR1 | AR2 | convolution ( difference of 2 expfunctions) | convolution | -| --------------------- | ---- | ---- | ---------------------------------------- | ----------- | -| FOOPSI[1] | √ | √ | √ | √ | -| Constrained-FOOPSI[2] | √ | | | | -| Thresholded-FOOPSI[3] | √ | √ | | | - - - -### Installation -Run setup.m to add OASIS function to the search path of MATLAB - -`>> setup` - -### Examples -The scripts to reproduce the figures are in the subfolder 'examples' with names obvious from the arXiv paper. They can be run with - -`>> run examples/paper/fig*.m ` - -There is also a function **deconvolveCa.m** wrapping all formulations of the problem. You might only need this one for your problem. See a list of examples in the demo script **oasis_test.m**, - -`>> edit examples/all_examples.m` - -### Benchmarks - - - -### References - -[1]Vogelstein, J.T., Packer, A.M., Machado, T.A., Sippy, T., Babadi, B., Yuste, R. and Paninski, L., 2010. Fast nonnegative deconvolution for spike train inference from population calcium imaging. *Journal of neurophysiology*,*104*(6), pp.3691-3704. - -[2]Pnevmatikakis, E.A., Soudry, D., Gao, Y., Machado, T.A., Merel, J., Pfau, D., Reardon, T., Mu, Y., Lacefield, C., Yang, W. and Ahrens, M., 2016. Simultaneous denoising, deconvolution, and demixing of calcium imaging data. *Neuron*, *89*(2), pp.285-299. - -[3]Friedrich, J., Zhou, P., and Paninski, L., 2016. Fast Active Set Methods for Online Deconvolution of Calcium Imaging Data. *arXiv preprint arXiv:*1609.00639. \ No newline at end of file diff --git a/deconvolveCa/constrained-foopsi/.gitignore b/deconvolveCa/constrained-foopsi/.gitignore deleted file mode 100644 index 25d91a6..0000000 --- a/deconvolveCa/constrained-foopsi/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ - -*.m~ -*.gif diff --git a/deconvolveCa/constrained-foopsi/MCEM_foopsi.m b/deconvolveCa/constrained-foopsi/MCEM_foopsi.m deleted file mode 100644 index 0e7b727..0000000 --- a/deconvolveCa/constrained-foopsi/MCEM_foopsi.m +++ /dev/null @@ -1,135 +0,0 @@ -function [c,b,c1,g,sn,sp] = MCEM_foopsi(y,b,c1,g,sn,options) - defoptions.dt = 1; - defoptions.MaxIter = 10; - defoptions.MaxInerIter = 50; - defoptions.TauStd = [0.2,2]; - defoptions.default_g = [0.6,0.9]; - - if nargin < 6; options.defoptions; end - if ~isfield(options,'dt'); options.dt = defoptions.dt; end - if ~isfield(options,'MaxIter'); options.MaxIter = defoptions.MaxIter; end - if ~isfield(options,'MaxInerIter'); options.MaxInerIter = defoptions.MaxInerIter; end - if ~isfield(options,'TauStd'); options.TauStd = defoptions.TauStd; end - if ~isfield(options,'default_g'); options.default_g = defoptions.default_g; end - - dt = options.dt; - - if nargin < 5 - sn = []; - if nargin < 4 - g = []; - if nargin < 3 - c1 = []; - if nargin < 2 - b = []; - end - end - end - end - - -% initialization - - [c,b,c1,g,sn,sp] = constrained_foopsi(y,b,c1,g,sn,options); - T = length(y); - p = length(g); - gr_ = sort(roots([1,-g(:)'])); - if p == 1; gr_ = [0,gr_]; end - if any(gr_<0) || any(~isreal(gr_)) - gr_ = options.default_g; - end - tau = -dt./log(gr_); - if p == 1 - gr_(1) = 0; - G1sp = zeros(T,1); - else - G1sp = make_G_matrix(T,gr_(1))\sp(:); - end - tau1_std = max(tau(1)/5,options.TauStd(1)); - tau2_std = min(tau(2)/10,options.TauStd(2)); - tauMoves = [0 0]; - tau_min = 0; - tau_max = 2*tau(2); - gd_vec = max(gr_).^(0:T-1)'; - tau_sam = zeros(options.MaxIter,2); - for iter = 1:options.MaxIter - TAU = zeros(options.MaxInerIter,2); - for iner_iter = 1:options.MaxInerIter - if p >= 2 % update rise time constant - logC = -norm(y(:) - c(:) - b - c1*gd_vec(:))^2; - tau_ = tau; - tau_temp = tau_(1)+(tau1_std*randn); - while tau_temp >tau(2) || tau_temptau_max || tau_temp - min | sum(sp)
- c,sp,b,c1 |
- subject to: sp| >= 0
- b| >= 0
- G*c| = sp
- c1| >= 0
- ||y-b-c - c_in|| | <= sn*sqrt(T)
- - -File constained_foopsi.m - Variables: |
----------------|----------------- - y: | raw fluorescence data (vector of length(T))
- c: | denoised calcium concentration (Tx1 vector)
- b: | baseline concentration (scalar)
- c1: | initial concentration (scalar)
- g: | discrete time constant(s) (scalar or 2x1 vector)
- sn: | noise standard deviation (scalar)
- sp: | spike vector (Tx1 vector)
- - USAGE:
- [c,b,c1,g,sn,sp] = constrained_foopsi(y,b,c1,g,sn,OPTIONS)
- The parameters b,cin,g,sn can be given or else are estimated from the data - - OPTIONS: (stuct for specifying options)
- p: order for AR model, used when g is not given (default 2)
- method: methods for performing spike inference
- available methods: 'dual' uses dual ascent
- 'cvx' uses the cvx package available from cvxr.com (default)
- 'lars' uses the least regression algorithm
- 'spgl1' uses the spgl1 package available from math.ucdavis.edu/~mpf/spgl1/ (usually fastest)
- bas_nonneg: flag for setting the baseline lower bound. if 1, then b >= 0 else b >= min(y)
- noise_range: frequency range over which the noise power is estimated. Default [Fs/4,Fs/2]
- noise_method: method to average the PSD in order to obtain a robust noise level estimate
- lags: number of extra autocovariance lags to be considered when estimating the time constants
- resparse: number of times that the solution is resparsened (default 0). Currently available only with methods 'cvx', 'spgl'
- - -The noise is estimated with a power spectral density approach and the time constants from the signal autocovariance. - -The algorithm can also handle missing data (appearing as NaNs in y) due to motion artifacts or for super-resolution approaches - -The algorithm is presented in more detail in - -Pnevmatikakis, E. A., Gao, Y., Soudry, D., Pfau, D., Lacefield, C., Poskanzer, K., ... & Paninski, L. (2014). A structured matrix factorization framework for large scale calcium imaging data analysis. arXiv preprint arXiv:1409.2903. http://arxiv.org/abs/1409.2903 - -Toolbox Dependencies -======= -The signal processing toolbox is optional. If present it is used for computing the power spectral density and the autocovariance function. - -License -======= - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . diff --git a/deconvolveCa/constrained-foopsi/acknowledgements.txt b/deconvolveCa/constrained-foopsi/acknowledgements.txt deleted file mode 100644 index eaee8a5..0000000 --- a/deconvolveCa/constrained-foopsi/acknowledgements.txt +++ /dev/null @@ -1 +0,0 @@ -Thanks to D. Soudry, W. Yang and D. Greenberg diff --git a/deconvolveCa/constrained-foopsi/constrained_foopsi.m b/deconvolveCa/constrained-foopsi/constrained_foopsi.m deleted file mode 100644 index 43a411f..0000000 --- a/deconvolveCa/constrained-foopsi/constrained_foopsi.m +++ /dev/null @@ -1,298 +0,0 @@ -function [c,b,c1,g,sn,sp] = constrained_foopsi(y,b,c1,g,sn,options) -% spike inference using a constrained foopsi approach: -% min sum(sp) -% c,sp,b,c1 -% subject to: sp >= 0 -% b >= 0 -% G*c = sp -% c1 >= 0 -% ||y-b-c - c_in|| <= sn*sqrt(T) - -% Variables: -% y: raw fluorescence data (vector of length(T)) -% c: denoised calcium concentration (Tx1 vector) -% b: baseline concentration (scalar) -% c1: initial concentration (scalar) -% g: discrete time constant(s) (scalar or 2x1 vector) -% sn: noise standard deviation (scalar) -% sp: spike vector (Tx1 vector) - -% USAGE: -% [c,b,c1,g,sn,sp] = constrained_foopsi(y,b,c1,g,sn,OPTIONS) -% The parameters b,cin,g,sn can be given or else are estimated from the data - -% OPTIONS: (stuct for specifying options) -% p: order for AR model, used when g is not given (default 2) -% method: methods for performing spike inference -% available methods: 'dual' uses dual ascent -% 'cvx' uses the cvx package available from cvxr.com (default) -% 'lars' uses the least regression algorithm -% 'spgl1' uses the spgl1 package available from -% math.ucdavis.edu/~mpf/spgl1/ (usually fastest) -% bas_nonneg: flag for setting the baseline lower bound. if 1, then b >= 0 else b >= min(y) -% noise_range: frequency range over which the noise power is estimated. Default [Fs/4,Fs/2] -% noise_method: method to average the PSD in order to obtain a robust noise level estimate -% lags: number of extra autocovariance lags to be considered when estimating the time constants -% resparse: number of times that the solution is resparsened (default 0). Currently available only with methods 'cvx', 'spgl' -% fudge_factor: scaling constant to reduce bias in the time constant estimation (default 1 - no scaling) - -% Written by: -% Eftychios A. Pnevmatikakis, Simons Foundation, 2015 - -defoptions.p = 2; -defoptions.method = 'cvx'; -defoptions.bas_nonneg = 1; % nonnegativity option for baseline estimation -defoptions.noise_range = [0.25,0.5]; % frequency range over which to estimate the noise -defoptions.noise_method = 'logmexp'; % method for which to estimate the noise level -defoptions.lags = 5; % number of extra lags when computing the AR coefficients -defoptions.resparse = 0; % number of times to re-sparse solution -defoptions.fudge_factor = 1; % fudge factor for time constants - -if nargin < 6 - options = defoptions; - if nargin < 5 - sn = []; - if nargin < 4 - g = []; - if nargin < 3 - c1 = []; - if nargin < 2 - b = []; - end - end - end - end -end - -if ~isfield(options,'p'); options.p = defoptions.p; end -if ~isfield(options,'method'); options.method = defoptions.method; end -if ~isfield(options,'bas_nonneg'); options.bas_nonneg = defoptions.bas_nonneg; end -if ~isfield(options,'noise_range'); options.noise_range = defoptions.noise_range; end -if ~isfield(options,'noise_method'); options.noise_method = defoptions.noise_method; end -if ~isfield(options,'lags'); options.lags = defoptions.lags; end -if ~isfield(options,'resparse'); options.resparse = defoptions.resparse; end -if ~isfield(options,'fudge_factor'); options.fudge_factor = defoptions.fudge_factor; end - -method = options.method; -if isempty(b); - bas_est = 1; -else - bas_est = 0; -end -if isempty(c1) - c1_est = 1; -else - c1_est = 0; -end - -y = y(:); -T = length(y); -y_full = y; -mis_data = isnan(y); -E = speye(T); -E(mis_data,:) = []; - -if any(mis_data) - y_full(mis_data) = interp1(find(~mis_data),y(~mis_data),find(mis_data)); -end - - -if isempty(sn) - sn = GetSn(y_full,options.noise_range,options.noise_method); -end -if isempty(g) - g = estimate_time_constants(y_full,options.p,sn,options.lags); - while max(abs(roots([1,-g(:)']))>1) && options.p < 5 - warning('No stable AR(%i) model found. Checking for AR(%i) model \n',options.p,options.p+1); - options.p = options.p + 1; - g = estimate_time_constants(y,options.p,sn,options.lags); - end - if options.p == 5 - g = 0; - end - %fprintf('Stable AR(%i) model found \n',options.p); - % re-adjust time constant values - rg = roots([1;-g(:)]); - if ~isreal(rg); rg = real(rg) + .001*randn(size(rg)); end - rg(rg>1) = 0.95 + 0.001*randn(size(rg(rg>1))); - rg(rg<0) = 0.15 + 0.001*randn(size(rg(rg<0))); - pg = poly(options.fudge_factor*rg); - g = -pg(2:end); -end -if options.bas_nonneg % lower bound for baseline - b_lb = 0; -else - b_lb = min(y); -end - -if strcmpi(method,'dual'); method = 'dual'; -elseif strcmpi(method,'cvx'); method = 'cvx'; -elseif strcmpi(method,'lars'); method = 'lars'; -elseif strcmpi(method,'spgl1'); method = 'spgl1'; -else fprintf('Invalid choice of method. Using CVX \n'); method = 'cvx'; -end - -if strcmpi(method,'dual') && any(mis_data) - warning('Dual method does not support missing data. Switching to CVX'); - method = 'cvx'; -end - -if options.resparse > 0 && (strcmpi(method,'dual') || strcmpi(method,'lars')) - warning('Resparsening is not supported with chosen method. Switching to CVX'); - method = 'cvx'; -end - -pathCell = regexp(path, pathsep, 'split'); -g = g(:); -G = spdiags(ones(T,1)*[-g(end:-1:1)',1],-length(g):0,T,T); -gd = max(roots([1,-g'])); % decay time constant for initial concentration -gd_vec = gd.^((0:T-1)'); - -switch method - case 'dual' - v = G'*ones(T,1); - thr = sn*sqrt(T-sum(mis_data)); - if bas_est; b = 0; end - if c1_est; c1 = 0; end - myfun = @(Ald) lagrangian_temporal_gradient(Ald,thr^2,y(~mis_data)-b-c1*gd_vec(~mis_data),bas_est,c1_est); - c = [G\max(G*y,0);zeros(bas_est);zeros(c1_est)]; - options_dual = optimset('GradObj','On','Display','Off','Algorithm','interior-point','TolX',1e-8); - ld_in = 10; - [ld,~,flag] = fmincon(myfun,ld_in,[],[],[],[],0,[],[],options_dual); - if (flag == -2) || (flag == -3) - warning('Problem seems unbounded or infeasible. Try a different method.'); - end - if bas_est; b = c(T+bas_est); end - if c1_est; c1 = c(end); end - c = c(1:T); - sp = G*c; - case 'cvx' - onPath = ~isempty(which('cvx_begin')); - if onPath - c = zeros(T,1+options.resparse); - sp = zeros(T,1+options.resparse); - bas = zeros(1+options.resparse,1); - cin = zeros(1+options.resparse,1); - w_ = ones(T,1); - for rep = 1:options.resparse+1 - [c(:,rep),bas(rep),cin(rep)] = cvx_foopsi(y,b,c1,sn,b_lb,g,w_,~mis_data); - sp(:,rep) = G*c(:,rep); - w_ = 1./(max(sp(:,rep),0) + 1e-8); - end - sp(sp<1e-6) = 0; - c = G\sp; - b = bas; - c1 = cin; - else - error('CVX does not appear to be on the MATLAB path. It can be downloaded from cvxr.com \n'); - end - case 'lars' - Ginv = E*[full(G\speye(T)),ones(T,bas_est),gd_vec*ones(1,c1_est)]; - if bas_est; b = 0; end - if c1_est; c1 = 0; end - [~, ~, spikes, ~, ~] = lars_regression_noise(y(~mis_data)-b_lb*bas_est - b - c1*gd_vec(~mis_data), Ginv, 1, sn^2*(T-sum(mis_data))); - sp = spikes(1:T); - b = (spikes(T+bas_est)+b_lb)*bas_est + b*(1-bas_est); - c1 = spikes(end)*c1_est + c1*(1-c1_est); - c = G\sp; - case 'spgl1' - onPath = ~isempty(which('spgl1')); - if onPath - Gx = @(x,mode) G_inv_mat(x,mode,T,g,gd_vec,bas_est,c1_est,E); - c = zeros(T,1+options.resparse); - sp = zeros(T,1+options.resparse); - bas = zeros(1+options.resparse,1); - cin = zeros(1+options.resparse,1); - w_ = ones(T,1); - for rep = 1:options.resparse+1 - if bas_est; b = 0; w_ = [w_;1e-10]; end - if c1_est; c1 = 0; w_ = [w_;1e-10]; end - options_spgl = spgSetParms('project',@NormL1NN_project ,'primal_norm', @NormL1NN_primal,'dual_norm',@NormL1NN_dual,'verbosity',0,'weights',w_); - [spikes,r,~,~] = spg_bpdn( Gx, y(~mis_data)-b_lb*bas_est - (1-bas_est)*b-(1-c1_est)*c1*gd_vec(~mis_data), sn*sqrt(T-sum(mis_data)),options_spgl); - c(:,rep) = G\spikes(1:T); %Gx([spikes(1:T);0],1); %% calcium signal - bas(rep) = b*(1-bas_est) + bas_est*spikes(T+bas_est)+b_lb*bas_est; %% baseline - cin(rep) = c1*(1-c1_est) + c1_est*spikes(end); - sp(:,rep) = spikes(1:T); %% spiking signal - w_ = 1./(spikes(1:T)+1e-8); - end - b = bas; - c1 = cin; - %sn = norm(r)/sqrt(T); - else - error('SPGL1 does not appear to be on the MATLAB path. It can be downloaded from math.ucdavis.edu/~mpf/spgl1 \n'); - end -end - - function sn = GetSn(Y,range_ff,method) - % estimate noise level with a power spectral density method - L=length(Y); -% if ~isempty(which('pmtm')) -% [psd_Y,ff] = pmtm(Y,5/2,1000,1); -% end - if ~isempty(which('pwelch')); - [psd_Y,ff]=pwelch(Y,round(L/8),[],1000,1); - else - xdft = fft(Y); - xdft = xdft(:,1:round(L/2)+1); - psd_Y = (1/L) * abs(xdft).^2; - ff = 0:1/L:1/2; - psd_Y(2:end-1) = 2*psd_Y(2:end-1); - end - ind=ff>range_ff(1); - ind(ff>range_ff(2))=0; - switch method - case 'mean' - sn=sqrt(mean(psd_Y(ind)/2)); - case 'median' - sn=sqrt(median(psd_Y(ind)/2)); - case 'logmexp' - sn = sqrt(exp(mean(log(psd_Y(ind)/2)))); - end - end - - - function g = estimate_time_constants(y,p,sn,lags) - % estimate time constants from the sample autocovariance function - - lags = lags + p; - if ~isempty(which('xcov')) %signal processing toolbox - xc = xcov(y,lags,'biased'); - else - ynormed = (y - mean(y)); - xc = nan(lags + 1, 1); - for k = 0:lags - xc(k + 1) = ynormed(1 + k:end)' * ynormed(1:end - k); - end - xc = [flipud(xc(2:end)); xc] / numel(y); - end - xc = xc(:); - A = toeplitz(xc(lags+(1:lags)),xc(lags+(1:p))) - sn^2*eye(lags,p); - g = pinv(A)*xc(lags+2:end); - end - - function [f,grad] = lagrangian_temporal_gradient(Al,thr,y_raw,bas_flag,c1_flag) - options_qp = optimset('Display','Off','Algorithm','interior-point-convex'); - H = [speye(T),ones(T,bas_flag),gd_vec*ones(1,c1_flag);... - ones(bas_flag,T),T*ones(bas_flag),(1-gd^T)/(1-gd)*ones(c1_flag,bas_flag);... - (gd_vec*ones(1,c1_flag))',(1-gd^T)/(1-gd)*ones(c1_flag,bas_flag),(1-gd^(2*T))/(1-gd^2)*ones(c1_flag,c1_flag)]; - Ay = [y_raw;sum(y_raw)*ones(bas_flag);gd_vec'*y_raw*ones(c1_flag)]; - c = quadprog(2*Al(1)*H,[v;zeros(bas_flag+c1_flag,1)]-2*Al(1)*Ay,[-G,sparse(T,bas_flag+c1_flag);sparse(bas_flag+c1_flag,T),-speye(bas_flag+c1_flag)]... - ,[sparse(T,1);-b_lb*ones(bas_flag);zeros(c1_flag)],[],[],[],[],c,options_qp); - f = v'*c(1:T); - grad = [sum((c(1:T)-y_raw + c(T+bas_flag)*bas_flag + c(end)*gd_vec*c1_flag).^2)-thr]; - f = f + Al(:)'*grad; - end - - function b = G_inv_mat(x,mode,NT,gs,gd_vec,bas_flag,c1_flag,Emat) - if mode == 1 - b = filter(1,[1;-gs(:)],x(1:NT)) + bas_flag*x(NT+bas_flag) + c1_flag*gd_vec*x(end); - b = Emat*b; - %b = G\x(1:NT) + x(NT+bas_flag)*bas_flag + x(end)*c1_flag; - elseif mode == 2 - x = Emat'*x; - b = [flipud(filter(1,[1;-gs(:)],flipud(x)));ones(bas_flag,1)*sum(x);ones(c1_flag,1)*(gd_vec'*x)]; - %b = [G'\x;ones(bas_flag,1)*sum(x);ones(c1_flag,1)*(gd_vec'*x)] ; - end - end - -end diff --git a/deconvolveCa/constrained-foopsi/cvx_foopsi.m b/deconvolveCa/constrained-foopsi/cvx_foopsi.m deleted file mode 100644 index 4fb92a1..0000000 --- a/deconvolveCa/constrained-foopsi/cvx_foopsi.m +++ /dev/null @@ -1,46 +0,0 @@ -function [c,b,c1] = cvx_foopsi(y,b,c1,sn,b_lb,g,w,keep) - -% implementation of constrained foopsi in CVX -% Written by Eftychios Pnevmatikakis - - if isempty(b) - bas_est = 1; - else - bas_est = 0; - end - if isempty(c1) - c1_est = 1; - else - c1_est = 0; - end - gd = max(roots([1,-g(:)'])); - T = length(y); - G = spdiags(ones(T,1)*[-g(end:-1:1)',1],-length(g):0,T,T); - gd_vec = gd.^((0:T-1)'); - cvx_begin quiet - variable c2(T) - if bas_est; variable b; end - if c1_est; variable c1; end - minimize(w'*(G*c2)) - subject to - G*c2>=0; - norm(y(keep)-c2(keep)-b-c1*gd_vec(keep))<=sqrt(sum(keep))*sn; - if bas_est; b>=b_lb; end - if c1_est; c1>=0; end - cvx_end - if strcmpi(cvx_status,'Infeasible'); - %disp('Problem is infeasible, adjusting noise value.'); - cvx_begin quiet - variable c2(T) - if bas_est; variable b; end - if c1_est; variable c1; end - minimize(norm(y(keep)-c2(keep)-b-c1*gd_vec(keep))) - subject to - G*c2>=0; - if bas_est; b>=b_lb; end - if c1_est; c1>=0; end - cvx_end - sn = cvx_optval/sqrt(sum(keep)); - end - c = c2; -end \ No newline at end of file diff --git a/deconvolveCa/constrained-foopsi/lars_regression_noise.m b/deconvolveCa/constrained-foopsi/lars_regression_noise.m deleted file mode 100644 index bfe70be..0000000 --- a/deconvolveCa/constrained-foopsi/lars_regression_noise.m +++ /dev/null @@ -1,286 +0,0 @@ -function [Ws, lambdas, W_lam, lam, flag] = lars_regression_noise(Y, X, positive, noise) - -% run LARS for regression problems with LASSO penalty, with optional positivity constraints -% Author: Eftychios Pnevmatikakis. Adapted code from Ari Pakman - - -% Input Parameters: -% Y: Y(:,t) is the observed data at time t -% X: the regresion problem is Y=X*W + noise -% maxcomps: maximum number of active components to allow -% positive: a flag to enforce positivity -% noise: the noise of the observation equation. if it is not -% provided as an argument, the noise is computed from the -% variance at the end point of the algorithm. The noise is -% used in the computation of the Cp criterion. - - -% Output Parameters: -% Ws: weights from each iteration -% lambdas: lambda values at each iteration -% Cps: C_p estimates -% last_break: last_break(m) == n means that the last break with m non-zero weights is at Ws(:,:,n) - - -verbose=false; -%verbose=true; - -k=1; - -T = size(Y,2); % # of time steps -N = size(X,2); % # of compartments - -maxcomps = N; - -W = zeros(N,k); -active_set = zeros(N,k); -visited_set = zeros(N,k); - -lambdas = []; - -Ws=zeros(size(W,1),size(W,2),maxcomps); % Just preallocation. Ws may end with more or less than maxcomp columns - - -%% - -r = X'*Y(:); % N-dim vector -M = -X'*X; % N x N matrix - -%% begin main loop - -%fprintf('\n i = '); -i = 1; -flag = 0; -while 1 - if flag == 1; - W_lam = 0; - break; - end - % fprintf('%d,',i); - - %% calculate new gradient component if necessary - - if i>1 && new && visited_set(new) ==0 - - visited_set(new) =1; % remember this direction was computed - - end - - %% Compute full gradient of Q - - dQ = r + M*W; - - %% Compute new W - if i == 1 - if positive - dQa = dQ; - else - dQa = abs(dQ); - end - [lambda, new] = max(dQa(:)); - - if lambda < 0 - disp('All negative directions!') - break - end - - else - - % calculate vector to travel along - -% disp('calc velocity') - - [avec, gamma_plus, gamma_minus] = calcAvec(new, dQ, W, lambda, active_set, M, positive); - - % calculate time of travel and next new direction - - if new==0 % if we just dropped a direction we don't allow it to emerge - if dropped_sign == 1 % with the same sign - gamma_plus(dropped) = inf; - else - gamma_minus(dropped) = inf; - end - end - - - gamma_plus(active_set == 1) = inf; % don't consider active components - gamma_plus(gamma_plus <= 0) = inf; % or components outside the range [0, lambda] - gamma_plus(gamma_plus> lambda) =inf; - [gp_min, gp_min_ind] = min(gamma_plus(:)); - - - if positive - gm_min = inf; % don't consider new directions that would grow negative - else - gamma_minus(active_set == 1) = inf; - gamma_minus(gamma_minus> lambda) =inf; - gamma_minus(gamma_minus <= 0) = inf; - [gm_min, gm_min_ind] = min(gamma_minus(:)); - - end - - [g_min, which] = min([gp_min, gm_min]); - - if g_min == inf; % if there are no possible new components, try move to the end - g_min = lambda; % This happens when all the components are already active or, if positive==1, when there are no new positive directions - end - - - - % LARS check (is g_min*avec too large?) - gamma_zero = -W(active_set == 1) ./ avec; - gamma_zero_full = zeros(N,k); - gamma_zero_full(active_set == 1) = gamma_zero; - gamma_zero_full(gamma_zero_full <= 0) = inf; - [gz_min, gz_min_ind] = min(gamma_zero_full(:)); - - if gz_min < g_min - if verbose - fprintf('DROPPING active weight: %d.\n', gz_min_ind) - end - active_set(gz_min_ind) = 0; - dropped = gz_min_ind; - dropped_sign = sign(W(dropped)); - W(gz_min_ind) = 0; - avec = avec(gamma_zero ~= gz_min); - g_min = gz_min; - new = 0; - - elseif g_min < lambda - if which == 1 - new = gp_min_ind; - if verbose - fprintf('new positive component: %d.\n', new) - end - else - new = gm_min_ind; - fprintf('new negative component: %d.\n', new) - end - end - - W(active_set == 1) = W(active_set == 1) + g_min * avec; - - if positive - if any (W<0) - min(W); - flag = 1; - %error('negative W component'); - end - end - - lambda = lambda - g_min; - end - - - - -%% Update weights and lambdas - - lambdas(i) = lambda; - Ws(:,:,i)=W; - res = norm(Y-X*W,'fro')^2; -%% Check finishing conditions - - - if lambda ==0 || (new && sum(active_set(:)) == maxcomps) || (res < noise) - if verbose - fprintf('end. \n'); - end - - break - end - -%% - if new - active_set(new) = 1; - end - - - i = i + 1; -end -%% end main loop - -%% final calculation of mus -if flag == 0 - if i > 1 - Ws= squeeze(Ws(:,:,1:length(lambdas))); - w_dir = -(Ws(:,i) - Ws(:,i-1))/(lambdas(i)-lambdas(i-1)); - Aw = X*w_dir; - y_res = Y - X*(Ws(:,i-1) + w_dir*lambdas(i-1)); - ld = roots([norm(Aw)^2,-2*(Aw'*y_res),y_res'*y_res-noise]); - lam = ld(intersect(find(ld>lambdas(i)),find(ld= 0; - norm(Y-X*W_lam)<= sqrt(noise); - cvx_end - lam = 10; - end -else - W_lam = 0; - Ws = 0; - lambdas = 0; - lam = 0; -end -end - -%%%%%%%%%% begin auxiliary functions %%%%%%%%%% - - -%% -function [avec, gamma_plus, gamma_minus] = calcAvec(new, dQ, W, lambda, active_set, M, positive) - -[r,c] = find(active_set); -Mm = -M(r,r); - - -Mm=(Mm + Mm')/2; - -% verify that there is no numerical instability -eigMm = eig(Mm); -if any(eigMm < 0) - min(eigMm) - %error('The matrix Mm has negative eigenvalues') - flag = 1; -end - - -b = sign(W); -if new - b(new) = sign(dQ(new)); -end -b = b(active_set == 1); - -avec = Mm\b; - -if positive - if new - in = sum(active_set(1:new)); - if avec(in) <0 - new; - %error('new component of a is negative') - flag = 1; - end - end -end - - - -one_vec = ones(size(W)); - -dQa = zeros(size(W)); -for j=1:length(r) - dQa = dQa + avec(j)*M(:, r(j)); -end - -gamma_plus = (lambda - dQ)./(one_vec + dQa); -gamma_minus = (lambda + dQ)./(one_vec - dQa); - -end diff --git a/deconvolveCa/constrained-foopsi/license.txt b/deconvolveCa/constrained-foopsi/license.txt deleted file mode 100644 index d159169..0000000 --- a/deconvolveCa/constrained-foopsi/license.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/deconvolveCa/deconvolveCa.m b/deconvolveCa/deconvolveCa.m deleted file mode 100644 index 75ed71d..0000000 --- a/deconvolveCa/deconvolveCa.m +++ /dev/null @@ -1,328 +0,0 @@ -function [c, s, options] = deconvolveCa(y, varargin) -%% infer the most likely discretized spike train underlying an fluorescence trace -%% Solves mutliple formulation of the problem -% 1) FOOPSI, -% mininize_{c,s} 1/2 * norm(y-c,2)^2 + lambda * norm(s,1) -% subject to c>=0, s>=0, s=Gc -% 2) constrained FOOPSI -% minimize_{c,s} norm(s, q) -% subject to norm(y-c,2) <= sn*sqrt(T), c>=0, s>=0, s=Gc -% where q is either 1 or 0, rendering the problem convex or non-convex. -% 3) hard threshrinkage -% minimize_{c,s} 1/2 * norm(y-c, 2)^2 -% subjec to c>=0, s=Gc, s=0 or s>=smin -% 4) Nonnegative least square problem (NNLS) -% min_{s} norm(y - s*h, 2)^2 + lambda * norm(s,1) -% subject to s>=0 - -%% inputs: -% y: T x 1 vector, fluorescence trace -% varargin: variable input arguments -% type: string, defines the model of the deconvolution kernel. possible -% options are: -% 'ar1': auto-regressive model with order p=1 -% 'ar2': auto-regressive model with order p=2 -% 'exp2': the convolution kernel is modeled as the difference of two -% exponential functions - -% h(t) = (exp(-t/tau_d) - exp(-t/tau_r)) / (tau_d-tau_r) -% 'kernel': a vector of the convolution kernel -% pars: parameters for the specified convolution kernel. it has -% different shapes for differrent types of the convolution model: -% 'ar1': scalar -% 'ar2': 2 x 1 vector, [r_1, r_2] -% 'exp2': 2 x 1 vector, [tau_r, tau_d] -% 'kernel': maxISI x 1 vector, the kernel. -% sn: scalar, standard deviation of the noise distribution. If no -% values is give, then sn is estimated from the data based on power -% spectual density method. -% b: fluorescence baseline vlaues. default is 0 -% optimize_pars: estimate the parameters of the convolution kernel. default: 0 -% optimize_b: estimate the baseline. default: 0 -% lambda: penalty parameter -% method: methods for running deconvolution. {'foopsi', -% 'constrained_foopsi' (default), 'thresholded'}, - -%% outputs: -% c: T x 1 vector, denoised trace -% s: T x 1 vector, deconvolved signal -% b: fluorescence baseline -% kernel: struct variable containing the parameters for the selected -% convolution model -% lambda: Optimal Lagrange multiplier for noise constraint under L1 penalty -% """olves the noise constrained sparse nonnegat - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% input arguments -y = reshape(y, [], 1); % reshape the trace as a vector -options = parseinputs(varargin{:}); % parse input arguments -if isempty(y) - c = []; s = []; - return; -end -win = options.window; % length of the convolution kernel -% estimate the noise -if isempty(options.sn) - options.sn = GetSn(y); -end -% estimate time constant -if isempty(options.pars) || all(options.pars==0) - switch options.type - case 'ar1' - try - options.pars = estimate_time_constant(y, 1, options.sn); - catch - c = y*0; - s = c; - fprintf('fail to deconvolve the trace\n'); - return; - end - if length(options.pars)~=1 - c = zeros(size(y)); - s = zeros(size(y)); - options.pars = 0; - return; - end - case 'ar2' - options.pars = estimate_time_constant(y, 2, options.sn); - if length(options.pars)~=2 - c = zeros(size(y)); - s = zeros(size(y)); - options.pars =[0,0]; - return; - end - case 'exp2' - g = estimate_time_constant(y, 2, options.sn); - options.pars = ar2exp(g); - case 'kernel' - g = estimate_time_constant(y, 2, options.sn); - taus = ar2exp(g); - options.pars = exp2kernel(taus, options.win); % convolution kernel - end -end - -%% run deconvolution -c = y; -s = y; -switch lower(options.method) - case 'foopsi' %% use FOOPSI - if strcmpi(options.type, 'ar1') % AR 1 - if options.smin<0 - options.smin = abs(options.smin)*options.sn; - end - - gmax = exp(-1/options.max_tau); - [c, s, options.b, options.pars] = foopsi_oasisAR1(y-options.b, options.pars, options.lambda, ... - options.smin, options.optimize_b, options.optimize_pars, [], options.maxIter, gmax); - elseif strcmpi(options.type, 'ar2') % AR 2 - if options.smin<0 - options.smin = abs(options.smin)*options.sn/max_ht(options.pars); - end - [c, s, options.b, options.pars] = foopsi_oasisAR2(y-options.b, options.pars, options.lambda, ... - options.smin); - elseif strcmpi(options.type, 'exp2') % difference of two exponential functions - kernel = exp2kernel(options.pars, options.window); - [c, s] = onnls(y-options.b, kernel, options.lambda, ... - options.shift, options.window); - elseif strcmpi(options.type, 'kernel') % convolution kernel itself - [c, s] = onnls(y-options.b, options.pars, options.lambda, ... - options.shift, options.window); - else - disp('to be done'); - end - case 'constrained' - if strcmpi(options.type, 'ar1') % AR1 - [c, s, options.b, options.pars, options.lambda] = constrained_oasisAR1(y,... - options.pars, options.sn, options.optimize_b, options.optimize_pars, ... - [], options.maxIter); - else - [cc, options.b, c1, options.pars, options.sn, s] = constrained_foopsi(y,[],[],options.pars,options.sn, ... - options.extra_params); - gd = max(roots([1,-options.pars'])); % decay time constant for initial concentration - gd_vec = gd.^((0:length(y)-1)); - c = cc(:) + c1*gd_vec'; - options.cin = c1; - end - case 'thresholded' %% Use hard-shrinkage method - if strcmpi(options.type, 'ar1') - [c, s, options.b, options.pars, options.smin] = thresholded_oasisAR1(y,... - options.pars, options.sn, options.optimize_b, options.optimize_pars, ... - [], options.maxIter, options.thresh_factor, options.p_noise); - % if and(options.smin==0, options.optimize_smin) % smin is given - % [c, s, options.b, options.pars, options.smin] = thresholded_oasisAR1(y,... - % options.pars, options.sn, options.optimize_b, options.optimize_pars, ... - % [], options.maxIter, options.thresh_factor); - % else - % [c, s] = oasisAR1(y-options.b, options.pars, options.lambda, ... - % options.smin); - % end - elseif strcmpi(options.type, 'ar2') - [c, s, options.b, options.pars, options.smin] = thresholded_oasisAR2(y,... - options.pars, options.sn, options.smin, options.optimize_b, options.optimize_pars, ... - [], options.maxIter, options.thresh_factor); - % if and(options.smin==0, options.optimize_smin) % smin is given - % [c, s, options.b, options.pars, options.smin] = thresholded_oasisAR2(y,... - % options.pars, options.sn, options.optimize_b, options.optimize_pars, ... - % [], options.maxIter, options.thresh_factor); - % else - % [c, s] = oasisAR2(y-options.b, options.pars, options.lambda, ... - % options.smin); - % end - elseif strcmpi(options.type, 'exp2') % difference of two exponential functions - d = options.pars(1); - r = options.pars(2); - options.pars = (exp(log(d)*(1:win)) - exp(log(r)*(1:win))) / (d-r); % convolution kernel - [c, s] = onnls(y-options.b, options.pars, options.lambda, ... - options.shift, options.window, [], [], [], options.smin); - elseif strcmpi(options.type, 'kernel') % convolution kernel itself - [c, s] = onnls(y-options.b, options.pars, options.lambda, ... - options.shift, options.window, [], [], [], options.smin); - else - disp('to be done'); - end - case 'mcmc' - SAMP = cont_ca_sampler(y,options.extra_params); - options.extra_params = SAMP; - options.mcmc_results = SAMP; - plot_continuous_samples(SAMP,y); -end - -function options=parseinputs(varargin) -%% parse input variables - -%% default options -options.type = 'ar1'; -options.pars = []; -options.sn = []; -options.b = 0; -options.lambda = 0; -options.optimize_b = false; -options.optimize_pars = false; -options.optimize_smin = false; -options.method = 'constrained'; -options.window = 200; -options.shift = 100; -options.smin = 0; -options.maxIter = 10; -options.thresh_factor = 1.0; -options.extra_params = []; -options.p_noise = 0.9999; -options.max_tau = 100; - -if isempty(varargin) - return; -elseif isstruct(varargin{1}) && ~isempty(varargin{1}) - tmp_options = varargin{1}; - field_nams = fieldnames(tmp_options); - for m=1:length(field_nams) - eval(sprintf('options.%s=tmp_options.%s;', field_nams{m}, field_nams{m})); - end - k = 2; -else - k = 1; -end -%% parse all input arguments -while k<=nargin - if isempty(varargin{k}) - k = k+1; - end - switch lower(varargin{k}) - case {'ar1', 'ar2', 'exp2', 'kernel'} - % convolution kernel type - options.type = lower(varargin{k}); - if (k -end -fprintf('FOOPSI: %.3f seconds\n', toc); -fprintf('\n**************AR 1**************\n'); - -%% AR(2) -% simulation -g = [1.7, -0.712]; -sn = 1; -seed = 3; -[Y, trueC, trueSpikes] = gen_data(g, sn, [], [], [], [], [], seed); -[N, T] = size(Y); - -% deconvolution -lam = 25; -[c_onnls, s_onnls] = onnls(Y(1,:), g, lam); -[c_foopsi, s_foopsi] = foopsi(Y(1,:), g, lam); -figure('papersize', [15, 4]); -init_fig; - -% plot results -figure('papersize', [15, 4]); -init_fig; - -% c -axes('position', [.05, .57, .46, .37]); -hold on; -plot(Y(1,:), 'color', col{8}/255, 'linewidth', 0.5); -alpha(.7); -plot(trueC(1,:), 'color', col{3}/255, 'linewidth', 1.5); -plot(c_onnls, 'color', col{1}/255); -plot(c_foopsi, '--', 'color', col{7}/255); -axis tight; -xlim([0, 1200]); -set(gca, 'xtick', 0:300:1500); -set(gca, 'xticklabel', []); -ylim(round([1+min(Y(1,:)), max(Y(1,:))-0.5])); -ylabel('Fluor.'); -box off; -% s -axes('position', [.05, .18, .46, .37]); -hold on; -plot(trueSpikes(1,:), 'color', col{3}/255, 'linewidth', 1.5); -plot(s_onnls, 'color', col{1}/255); -plot(s_foopsi, '--', 'color', col{7}/255); -axis tight; -xlim([0, 1200]); -set(gca, 'xtick', 0:300:1500); -set(gca, 'xticklabel', get(gca, 'xtick')/30); -set(gca, 'ytick', [0,1]); -xlabel('Time [s]'); -ylabel('Activity.'); - -%% timeit -fprintf('\n**************AR 2**************\n'); -tic; -for m=1:N - [c_onnls, s_onnls] = onnls(Y(m,:), g, lam); -end -fprintf('online NNLS: %.3f seconds\n', toc); - -tic; -for m=1:N - [c_foopsi, s_foopsi] = foopsi(Y(m,:), g, lam); -end -fprintf('FOOPSI: %.3f seconds\n', toc); -fprintf('\n**************AR 2**************\n'); - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/examples/Paper/fig4.m b/deconvolveCa/examples/Paper/fig4.m deleted file mode 100644 index ee8b7fc..0000000 --- a/deconvolveCa/examples/Paper/fig4.m +++ /dev/null @@ -1,150 +0,0 @@ -%% -close all; clc; -addpath('./scripts'); -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; -figure('papersize', [14.4, 7.2]); -init_fig; - -%% load the test data -gam = 0.95; -sn = .3; -T = 1500; -lam = 0; -load fig4_data; -y = reshape(y, [],1); -g = .9; -g0 = g; -ax0 = .06; -ax1 = .2; - -%% plot initial result -[solution, spks, active_set] = oasisAR1(y, g, lam); -axes('position', [ax1, 0.87, 1-ax1, .12]); -fig4_plot_trace; -legend('Data', 'Truth', 'Estimate', 'orientation', 'horizental',... - 'location', [0.01+ax1, 0.96, 0.35, 0.0345]); - -%% solve for lambda -c = solution; -temp = zeros(size(c)); -len_active_set = size(active_set,1); -for ii=1:len_active_set - ti = active_set(ii, 3); - li = active_set(ii, 4); - idx = 0:(li-1); - temp(ti+idx) = (1-g^li)/ active_set(ii,2) * g.^(idx); -end -res = y - solution; -aa = temp'*temp; -bb = res'*temp; -cc = res'*res - sn^2*T; -active_set_0 = active_set; -ll = (-bb + sqrt(bb^2-aa*cc)) / aa; -active_set_0(:,1) = active_set_0(:,1) - ll*(1-g.^(active_set_0(:,4))); -spks = 0*spks; -for ii=1:len_active_set - ti = active_set(ii, 3); - li = active_set(ii, 4); - idx = 0:(li-1); - solution(ti+idx) = active_set_0(ii,1)/active_set_0(ii,2) * (g.^(idx)); - if ii>1 - spks(ti) = solution(ti) - g*solution(ti-1); - end -end - -% plot results after updating lambda, but before running oasis to fix -% violations -axes('position', [ax1, .73, 1-ax1, .12]); -fig4_plot_trace; - -% plot the depence of RSS on lambda -lam_vec = linspace(0, 2.0, 100); -RSS_vec = zeros(size(lam_vec)); -for m=1:length(lam_vec); - RSS_vec(m) = norm((res-lam_vec(m)*temp),2)^2; -end - -axes('position', [ax0, .75, .08, .12]); hold on; -plot(lam_vec, RSS_vec, 'color', col{2}/255); - -% the optimal value -thresh = sn.^2 * T; -plot([-.1, ll], thresh*[1,1], 'k'); -plot([ll, ll], [100, thresh], 'k'); -scatter(0, RSS_vec(1), 50, col{1}/255); -xlim([0, 1.7]); -ylim([114, 138]); -set(gca,'ytick', thresh); -set(gca, 'yticklabel', '\sigma^2T'); -set(gca, 'xtick', [0,lam+ll]); -set(gca, 'xticklabel', {0, '\lambda^*'}); - -%% plot result after rerunning oasis to fix violations -lam = lam + ll; -[solution, spks, active_set] = oasisAR1(y, g, lam, [], active_set_0); -axes('position', [ax1, .59, 1-ax1, .12]); -fig4_plot_trace; -ylabel('Fluorescence'); - -%% solve for gamma -[~, ~, g] = update_g(y, active_set,g, lam); -axes('position', [ax0, .47, .08, .12]); hold on; -g_vec = linspace(.85, 0.99); -rss_vec = compute_rss_g(g_vec, y, active_set, lam); -plot(g_vec, rss_vec, 'color', col{2}/255); -xlim([min(g_vec), max(g_vec)]); -scatter(g0, compute_rss_g(g0, y, active_set, lam), 50, col{1}/255, 'filled'); -set(gca, 'xtick', g); -set(gca, 'xticklabel', '\gamma^*'); -set(gca,'ytick', thresh); -set(gca, 'yticklabel', '\sigma^2T'); -% plot result after updating gamma, but before rerunning oasis to fix -% violations -len_active_set = size(active_set, 1); -ma = max(active_set(:, 4)); -h = g.^((0:ma)'); -hh = cumsum(h.*h); -for ii=1:len_active_set - ti = active_set(ii,3); - li = active_set(ii,4); - idx = ti:(ti+li-1); - active_set(ii,1) = (y(idx)-lam*(1-g))'*h(1:li); - active_set(ii,2) = hh(li); -end -for ii=1:length(active_set_0) - ti = active_set_0(ii,3); - li = active_set_0(ii,4); - idx = ti:(ti+li-1); - solution(idx) = active_set_0(ii,1)/active_set_0(ii,2) * h(1:li); -end -solution(solution<0) = 0; -spks = [0; solution(2:end)-g*solution(1:(end-1))]; -axes('position', [ax1, .45, 1 - ax1, .12]); hold on; -fig4_plot_trace; - -%% plot result after rerunning oasis to fix violatiosn -[solution, spks, active_set] = oasisAR1(y, g, lam,[], active_set); -axes('position', [ax1, .31, 1 - ax1, .12]); hold on; -fig4_plot_trace; - -%% do more iterations -for miter=1:3 - [~, active_set, lam, ~] = update_lam(y, solution, active_set, g, lam, thresh); - [solution, active_set, g, spks] = update_g(y, active_set, g, lam); -end -axes('position', [ax1, .07, 1 - ax1, .12]); -hold on; -fig4_plot_trace; -sol_given_g = constrained_oasisAR1(y, .95, sn); -estimated_g = estimate_parameters(y, 1); -fprintf('\n*******************\n'); -fprintf('estimated gamma via autocorrelation: %.4f\n', estimated_g); -fprintf('optimized gamma : %.4f\n', g); -fprintf('\n*******************\n'); -sol_PSD_g = constrained_oasisAR1(y, estimated_g, 0); -h1 = plot(sol_given_g, '--', 'color', col{7}/255); -h2 = plot(sol_PSD_g, 'color', col{6}/255); -legend([h1, h2], 'true \gamma', '\gamma from autocovariance', ... - 'orientation', 'horizontal', 'location', [0.01+ax1, 0.16, 0.35, 0.0345]); -saveas(gcf, 'fig/opt_g+l_new.pdf') \ No newline at end of file diff --git a/deconvolveCa/examples/Paper/fig5.m b/deconvolveCa/examples/Paper/fig5.m deleted file mode 100644 index cc7440e..0000000 --- a/deconvolveCa/examples/Paper/fig5.m +++ /dev/null @@ -1,191 +0,0 @@ -%% -clear; clc; close all; -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; - -%% AR (1) -% simulation -g = .95; -sn = .3; -[Y, trueC, trueSpikes] = gen_data(g, sn, [], [],[], [], 1, 10); -y = Y(1, :); - -% run deconvolution -[c, s] = constrained_foopsi_cvx(y, g, sn); -[c_t, s_t] = oasisAR1(y, g, 0, .55); - -% check the dependence on smin -smin = 0:0.1:1.1; -res = zeros(length(smin), length(y)); -for m=1:length(smin) - [~, res(m, :)] = oasisAR1(y, g, 0, smin(m)); -end -% plot results -figure('papersize', [10,9]); -init_fig; -ymax = ceil(max(y)*2)/2; -ymin = quantile(y(1:500), 0.02); -% c -axes('position', [.13, .7, .86, .29]); hold on; -plot(y, 'color', col{8}/255); -alpha(.7); -plot(trueC(1, :), 'color', col{3}/255, 'linewidth', 3); -plot(c, 'color', col{1}/255); -plot(c_t, 'color', col{2}/255); -legend('Data', 'Truth', 'Thresh', 'L1', 'orientation', 'horizental'); -ylim([ymin, ymax]); -xlim([0, 452]); -set(gca, 'xtick', 0:150:500); -set(gca, 'xticklabel', []); -set(gca, 'ytick', 0:1:ymax); -ylabel('Fluor.'); - -%s -axes('position', [.13, .39, .86, .29]); hold on; -for m=find(trueSpikes(1,1:500)) - plot([m, m], [0, 1], 'color', col{3}/255); -end -plot([0, 450], [0, 0], 'color', col{3}/255); -for m=find(s(1:500)) - plot([m, m], [0, s(m)]+2.5, 'color', col{1}/255); -end -plot([0, 450], [1, 1]*2.5, 'color', col{1}/255); -for m=find(s_t(1:500)') - plot([m, m], [0, s_t(m)]+1.25, 'color', col{2}/255); -end -plot([0, 450], [1, 1]*1.25, 'color', col{2}/255); - -ylim([0, 3.5]); -xlim([0, 452]); -set(gca, 'xtick', 0:150:500); -set(gca, 'xticklabel', []); -set(gca, 'ytick', 0:1.25: 2.5); -set(gca, 'yticklabel', {'Thresh.', 'Truth', 'L1'}) - -% dependence on smin -axes('position', [.13, .08, .86, .29]); hold on; -for m=find(trueSpikes(1,1:500)) - plot([m, m], [-.08, -0.16], 'r'); -end -for rr=1:length(smin) - for m=find(res(rr, 1:500)) - plot([m, m], rr*.1+[-0.14, -0.06], 'color', 'k'); - end -end - -ylim([-0.2, smin(end)]); -xlim([0, 452]); -set(gca, 'xtick', 0:150:500); -set(gca, 'xticklabel', get(gca, 'xtick')/30) -set(gca, 'ytick', 0:0.5:1); -ylabel('s_{min}'); - -saveas(gcf, 'fig/threshAR1.pdf'); - - -%% AR (2) -% simulation -g = [1.7, -0.712]; -sn = 1; -seed = 1; -[Y, trueC, trueSpikes] = gen_data(g, sn, [],[],[],[], [], seed); -% Y(:, 1:150) = []; -% trueC(:,1:150) = []; -% trueSpikes(:,1:150) = []; -y = Y(1, :); - -% run deconvolution -[c, s] = constrained_foopsi_cvx(y, g, sn); -[c_t, s_t] = oasisAR2(y, g, 0, .55); - -% check the dependence on smin -smin = 0:0.1:1.1; -res = zeros(length(smin), length(y)); -for m=1:length(smin) - [~, res(m, :)] = oasisAR2(y, g, 0, smin(m)); -end -% plot results -figure('papersize', [10,9]); -init_fig; -ymax = ceil(max(y)*2)/2; -ymin = quantile(y(1:500), 0.02); -% c -axes('position', [.13, .7, .86, .29]); hold on; -plot(y, 'color', col{8}/255); -alpha(.7); -plot(trueC(1, :), 'color', col{3}/255, 'linewidth', 3); -plot(c, 'color', col{1}/255); -plot(c_t, 'color', col{2}/255); -legend('Data', 'Truth', 'Thresh', 'L1', 'orientation', 'horizental'); -ylim([ymin, ymax]); -xlim([0, 452]); -set(gca, 'xtick', 0:150:500); -set(gca, 'xticklabel', []); -set(gca, 'ytick', 0:1:ymax); -ylabel('Fluor.'); - -%s -axes('position', [.13, .39, .86, .29]); hold on; -for m=find(trueSpikes(1,1:500)) - plot([m, m], [0, 1], 'color', col{3}/255); -end -plot([0, 450], [0, 0], 'color', col{3}/255); -for m=find(s(1:500)) - plot([m, m], [0, s(m)]+2.5, 'color', col{1}/255); -end -plot([0, 450], [1, 1]*2.5, 'color', col{1}/255); -for m=find(s_t(1:500)') - plot([m, m], [0, s_t(m)]+1.25, 'color', col{2}/255); -end -plot([0, 450], [1, 1]*1.25, 'color', col{2}/255); - -ylim([0, 3.5]); -xlim([0, 452]); -set(gca, 'xtick', 0:150:500); -set(gca, 'xticklabel', []); -set(gca, 'ytick', 0:1.25: 2.5); -set(gca, 'yticklabel', {'Thresh.', 'Truth', 'L1'}) - -% dependence on smin -axes('position', [.13, .08, .86, .29]); hold on; -for m=find(trueSpikes(1,1:500)) - plot([m, m], [-.08, -0.16], 'r'); -end -for rr=1:length(smin) - for m=find(res(rr, 1:500)) - plot([m, m], rr*.1+[-0.14, -0.06], 'color', 'k'); - end -end - -ylim([-0.2, smin(end)]); -xlim([0, 452]); -set(gca, 'xtick', 0:150:500); -set(gca, 'xticklabel', get(gca, 'xtick')/30) -set(gca, 'ytick', 0:0.5:1); -ylabel('s_{min}'); - -saveas(gcf, 'fig/threshAR2.pdf'); - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/examples/Paper/fig6.m b/deconvolveCa/examples/Paper/fig6.m deleted file mode 100644 index 0d6d0c4..0000000 --- a/deconvolveCa/examples/Paper/fig6.m +++ /dev/null @@ -1,7 +0,0 @@ -%% -close all; clc; -addpath('./scripts'); -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; -figure('papersize', [14, 7]); -init_fig; \ No newline at end of file diff --git a/deconvolveCa/examples/Paper/scripts/compute_rss_g.m b/deconvolveCa/examples/Paper/scripts/compute_rss_g.m deleted file mode 100644 index 503eb36..0000000 --- a/deconvolveCa/examples/Paper/scripts/compute_rss_g.m +++ /dev/null @@ -1,65 +0,0 @@ -function rss_vec = compute_rss_g(g, y, Aset, lam) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% Aset: npools*4 matrix, previous active sets -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, curret value of sparsity penalty parameter lambda. - -%% outputs -% rss_vec: vector with the same elements as g. - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% initialization -len_active_set = size(Aset, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(Aset(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% function for computing the optimal RSS given fixed AR coefficient g and the active set - function rss = rss_g(g) - yp = y - lam*(1-g); % include the penalty term - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - for ii=1:len_active_set - li = Aset(ii, 4); - ti = Aset(ii, 3); - idx = ti:(ti+li-1); - tmp_v = yp(idx)' * h(1:li) / hh(li); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end - -rss_vec = zeros(size(g)); -for m=1:length(g) - rss_vec(m) = rss_g(g(m)); -end -end - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/examples/Paper/scripts/fig2_demo_deconvolveAR1.m b/deconvolveCa/examples/Paper/scripts/fig2_demo_deconvolveAR1.m deleted file mode 100644 index cabaf37..0000000 --- a/deconvolveCa/examples/Paper/scripts/fig2_demo_deconvolveAR1.m +++ /dev/null @@ -1,222 +0,0 @@ -function c = fig2_demo_deconvolveAR1(y, g, lam, video, trueSpikes) -%% extract neural activity from a fluorescence trace using an active set -% method for sparse nonnegative deconvolution - -%% inputs: -% y: T*1 vector, raw fluorescence trace -% g: scalar, AR(1) coefficient -% lam: scalar, tuning parameter for sparsity - -%% outputs -% c: T*1 vector, denoised trace - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% proted from the Python implementation from Johannes Friedrich - -%% initialization -y = reshape(y, [], 1); -if ~exist('g', 'var') || isempty(g); g = 0.95; end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end - -len_active_set = length(y); -Aset = ones(len_active_set, 4); % each row is one pool: (vi, wi, t, l) -Aset(:,1) = y - lam; % vi -Aset(:,3) = (1:len_active_set); % ti -Aset(end, 1) = y(end) - lam/(1-g); -Aset(end, 3) = len_active_set; -Aset(1,1) = max(Aset(1,1), 0); - -%% run OASIS -ii = 1; -counter = 1; -if video - figure('papersize', [15, 6]); - init_fig; - avi_file = VideoWriter('fig/Video.avi'); - avi_file.FrameRate = 10; - avi_file.open(); -else - figure('papersize', [3,3]); - init_fig; -end -while ii < len_active_set - % find the active set - while (ii=Aset(ii,1)*g^(Aset(ii,4))) - ii = ii + 1; - end - - if ii == len_active_set; break; end - - if video - cb_video(y, Aset, g, ii, trueSpikes); - avi_file.writeVideo(getframe(gcf)); - else - cb(y, Aset, g, counter, ii, trueSpikes); - end - counter = counter+1; - %% merge pools - while ii>0 && (Aset(ii+1,1) < Aset(ii,1)*g^(Aset(ii,4))) - temp = Aset(ii,2) + Aset(ii+1,2)*(g^(2*Aset(ii, 4))); - Aset(ii,1) = (Aset(ii,1)*Aset(ii,2) + Aset(ii+1,1)*Aset(ii+1, 2)* ... - (g^(Aset(ii,4)))) / temp; - if ii==1 - Aset(ii,1) = max(Aset(ii,1), 0); - end - Aset(ii, 2) = temp; - Aset(ii, 4) = Aset(ii, 4) + Aset(ii+1, 4); - Aset(ii+1, :) = []; - ii = ii - 1; - end - - ii = ii + 1; - len_active_set = size(Aset,1); -end - -%% construct solution for all t -c = zeros(size(y)); -c(Aset(:, 3)) = Aset(:, 1); -for ii=1:len_active_set - t0 = Aset(ii,3); - tau = Aset(ii, 4); - c(t0:(t0+tau-1)) = Aset(ii,1) * (g.^(0:(tau-1))); -end -if video - avi_file.close(); -end -end - -function cb(y, Aset, g, counter, current, trueSpikes) -%% function for taking snapshot of OASIS procedures -if ~exist('fig', 'dir') - mkdir fig; -end -len_active_set = size(Aset,1); -% construct solution -c = zeros(size(y)); -Aset(:,1) = max(0, Aset(:, 1)); -c(Aset(:, 3)) = Aset(:, 1); -for ii=1:len_active_set - t0 = Aset(ii,3); - tau = Aset(ii, 4); - c(t0:(t0+tau-1)) = Aset(ii,1) * (g.^(0:(tau-1))); -end -% plot results -clf; hold on; -% use different color to separate pools -ymax = 1.2; -for m=1:2:len_active_set - t0 = Aset(m, 3); - t1 = Aset(m, 3) + Aset(m, 4); - fill([t0+0.1, t1, t1, t0+0.1], [0.01, 0.01, ymax, ymax], [1,1,1]*0.9, 'edgecolor', 'w'); -end -temp = find(trueSpikes); -for m=1:length(temp); - plot([1, 1]*temp(m), [0, ymax], 'r', 'linewidth', 3); -end -ind = 48-ceil((y-min(y))/range(y)*16); -col_map = jet(); -col = col_map(ind, :); -% current estimation of c -plot(c, 'color', 'k', 'linewidth', 2); -scatter(1:length(y), c, 100, col, 'filled', 'markeredgecolor', 'k'); -% scatter plot the current pool -t = Aset(current, 3)+(1:Aset(current, 4)); -plot(t, c(t), '+b', 'markersize', 10); -ylim([-0, ymax]); -xlim([1, length(y)-1]); -set(gca, 'xtick', []); -set(gca, 'ytick', []); -box off; -pause(.1); -saveas(gcf, sprintf('fig/%d.pdf', counter)); -end - - -function cb_video(y, Aset, g, current, trueSpikes) -%% function for taking snapshot of OASIS procedures and save the results as a video -if ~exist('fig', 'dir') - mkdir fig; -end -len_active_set = size(Aset,1); -% construct solution -c = zeros(size(y)); -c(Aset(:, 3)) = Aset(:, 1); -for ii=1:len_active_set - t0 = Aset(ii,3); - tau = Aset(ii, 4); - c(t0:(t0+tau-1)) = Aset(ii,1) * (g.^(0:(tau-1))); -end -s = c; -for t=2:length(y) - s(t) = c(t) - g*c(t-1); -end -% plot results -clf; -axes('position', [0.05, 0.55, 0.9, 0.4]); cla; hold on; -ymax = 1.8; -% use different color to separate pools -for m=1:2:len_active_set - t0 = Aset(m, 3); - t1 = Aset(m, 3) + Aset(m, 4); - fill([t0, t1, t1, t0], [0.01, 0.01, ymax, ymax], [1,1,1]*0.9, 'edgecolor', 'w'); -end -temp = find(trueSpikes); -for m=1:length(temp); - plot([1, 1]*temp(m), [0, ymax], 'r', 'linewidth', 3); -end -ax = gca; -ax.XAxisLocation = 'origin'; -plot([0, 0], [-0.6, 0], 'w', 'linewidth', 4); -plot([0, length(y)], [0, 0], 'k', 'linewidth', 4); -plot([0, 0], [0, ymax], 'k', 'linewidth', 4); - -ind = 48-ceil((y-min(y))/range(y)*16); -col_map = jet(); -col = col_map(ind, :); -% current estimation of c -plot(c, 'color', 'k', 'linewidth', 2); -scatter(1:length(y), c, 80, col, 'filled', 'markeredgecolor', 'k'); -% scatter plot the current pool -t = Aset(current, 3)+(1:Aset(current, 4)); -plot(t, c(t), '+b', 'markersize', 10); -ylim([-0.6, ymax]); -xlim([0, length(y)-1]); -set(gca, 'xtick', []); -set(gca, 'ytick', []); -ylabel('Fluorescence'); - -%% plot spike trains -axes('position', [0.05, 0.1, 0.9, 0.4]); cla; hold on; -ymax = 1.5; -% use different color to separate pools -for m=1:2:len_active_set - t0 = Aset(m, 3); - t1 = Aset(m, 3) + Aset(m, 4); - fill([t0, t1, t1, t0], [0.01, 0.01, ymax, ymax], [1,1,1]*0.9, 'edgecolor', 'w'); -end -temp = find(trueSpikes); -for m=1:length(temp); - plot([1, 1]*temp(m), [0, ymax], 'r', 'linewidth', 3); -end -ax = gca; -ax.XAxisLocation = 'origin'; -plot([0, 0], [-0.6, 0], 'w', 'linewidth', 4); -plot([0, length(y)], [0, 0], 'k', 'linewidth', 4); -plot([0, 0], [0, ymax], 'k', 'linewidth', 4); -s = c; -plot([1,1], [0, s(1)], 'k', 'linewidth', 3); -for t=2:length(y) - s(t) = c(t) - g*c(t-1); - plot([t, t], [0, s(t)], 'k', 'linewidth', 3); -end -scatter(1:length(y), s, 80, col, 'filled', 'markeredgecolor', 'k'); -% scatter plot the current pool -t = Aset(current, 3)+(1:Aset(current, 4)); -plot(t, s(t), '+b', 'markersize', 10); -ylim([-0.6, ymax]); -xlim([0, length(y)-1]); -set(gca, 'xtick', []); -set(gca, 'ytick', []); -ylabel('Spikes'); -xlabel('Time'); -end \ No newline at end of file diff --git a/deconvolveCa/examples/Paper/scripts/fig4_plot_trace.m b/deconvolveCa/examples/Paper/scripts/fig4_plot_trace.m deleted file mode 100644 index 07f6bd2..0000000 --- a/deconvolveCa/examples/Paper/scripts/fig4_plot_trace.m +++ /dev/null @@ -1,16 +0,0 @@ -plot(y, 'color', col{8}/255, 'linewidth', 1); -hold on; -plot(trueC, 'color', col{3}/255); -plot(solution, 'color', col{1}/255); -text(700, 2.8, sprintf('Correlation: %.3f', corr(trueS, spks)), ... - 'fontweight', 'bold', 'fontsize', 16); -xlim([0, 1500]); -ylim([min(y), 3.3]); -ax = gca; -ax.XAxisLocation = 'origin'; -ax.YAxisLocation = 'origin'; -set(gca, 'ytick', 0:2:max(y)); -set(gca, 'xtick', 0:300:1200); -set(gca, 'xticklabel', []); -set(gca, 'yticklabel', [0,2]); -box off; \ No newline at end of file diff --git a/deconvolveCa/examples/Paper/scripts/show_results.m b/deconvolveCa/examples/Paper/scripts/show_results.m deleted file mode 100644 index ad86773..0000000 --- a/deconvolveCa/examples/Paper/scripts/show_results.m +++ /dev/null @@ -1,29 +0,0 @@ -init_fig; - -% c -axes('position', [.05, .57, .95, .37]); -hold on; -plot(y, 'color', col{8}/255); -alpha(.7); -plot(true_c, 'color', col{3}/255, 'linewidth', 1.5); -plot(c_oasis, '-.', 'color', col{1}/255); -axis tight; -xlim([0, 2000]); -set(gca, 'xtick', [0, 25, 50, 75]*30); -set(gca, 'xticklabel', []); -set(gca, 'ytick', 0:2); -ylabel('Fluor.'); -box off; -legend('Data', 'Truth', 'OASIS', 'location', 'northeast', 'orientation', 'horizental'); -% s -axes('position', [.05, .18, .95, .37]); -hold on; -plot(true_s, 'color', col{3}/255, 'linewidth', 1.5); -plot(s_oasis, '-.', 'color', col{1}/255); -axis tight; -xlim([0, 2000]); -set(gca, 'xtick', [0, 25, 50, 75]*30); -set(gca, 'xticklabel', get(gca, 'xtick')/30); -set(gca, 'ytick', [0,1]); -xlabel('Time [s]'); -ylabel('Activity.'); \ No newline at end of file diff --git a/deconvolveCa/examples/Paper/test_all.m b/deconvolveCa/examples/Paper/test_all.m deleted file mode 100644 index 0170178..0000000 --- a/deconvolveCa/examples/Paper/test_all.m +++ /dev/null @@ -1,5 +0,0 @@ -fig1; -fig2; -fig3; -fig4; -fig5; \ No newline at end of file diff --git a/deconvolveCa/examples/ar1_constrained_foopsi.m b/deconvolveCa/examples/ar1_constrained_foopsi.m deleted file mode 100644 index f90ab69..0000000 --- a/deconvolveCa/examples/ar1_constrained_foopsi.m +++ /dev/null @@ -1,74 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 7: constrained-foopsi, AR1 -g = 0.95; % AR coefficient -noise = .3; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 1; % number of trials -seed = 13; % seed for genrating random variables -[y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); - -% cvx solution -[c_cvx, s_cvx] = constrained_foopsi(y, g, noise); -% case 1: all parameters are known -[c_oasis, s_oasis] = deconvolveCa(y, 'ar1', g, 'constrained', 'sn', noise); %#ok<*ASGLU> - -figure('name', 'constrained-FOOPSI, AR1, known: g, sn', 'papersize', [15, 4]); -plot_cvx = true; -show_results; -plot_cvx = false; - -% case 2: nothing is known, estimate g with auto-correlation method -[c_oasis, s_oasis,options] = deconvolveCa(y, 'ar1', 'constrained'); - -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); - -figure('name', 'FOOPSI, AR1, estimated: g, sn', 'papersize', [15, 4]); -show_results; - -% case 3: nothing is know, estimate g with auto-correlation method first -% and then update it to minimize the RSS -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'constrained', ... - 'optimize_pars'); - -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); - -figure('name', 'FOOPSI, AR1, estimated: g, sn, update:g', 'papersize', [15, 4]); -show_results; - -% case 4: nothing is know, estimate g with auto-correlation method first -% and then update it to minimize the RSS, the baseline is also unknown -true_b = 0.5; -[c_oasis, s_oasis, options] = deconvolveCa(y+true_b, 'ar1', g,... - 'constrained','optimize_b', 'sn', noise); -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); -fprintf('true b: %.3f\n', true_b); -fprintf('estimated b: %.3f\n', options.b); -fprintf('tuning parameter: %.3f\n', options.lambda); - -figure('name', 'FOOPSI, AR1, estimated: g, sn, lambda', 'papersize', [15, 4]); -show_results; - -% case 5: nothing is know, estimate g with auto-correlation method first -% and then update it to minimize the RSS, the baseline is also unknown -true_b = 0.5; -[c_oasis, s_oasis, options] = deconvolveCa(y+true_b, 'ar1',... - 'constrained','optimize_b', 'optimize_pars'); -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); -fprintf('estimated b: %.3f\n', options.b); -fprintf('tuning parameter: %.3f\n', options.lambda); - -figure('name', 'FOOPSI, AR1, estimated: g, sn, lambda, update:g', 'papersize', [15, 4]); -show_results; - -%% \ No newline at end of file diff --git a/deconvolveCa/examples/ar1_foopsi.m b/deconvolveCa/examples/ar1_foopsi.m deleted file mode 100644 index 984a9c9..0000000 --- a/deconvolveCa/examples/ar1_foopsi.m +++ /dev/null @@ -1,47 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 1: foopsi, AR1 model. This model is used when the sampling rate is low -g = 0.95; % AR coefficient -noise = .3; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 1; % number of trials -seed = 13; % seed for genrating random variables -[y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); - -% case 1: all parameters are known -lambda = 2.4; -[c_oasis, s_oasis] = deconvolveCa(y, 'ar1', g, 'foopsi', 'lambda', lambda); %#ok<*ASGLU> -[c_cvx, s_cvx] = foopsi(y, g, lambda); - -figure('name', 'FOOPSI, AR1, known: g, lambda', 'papersize', [15, 4]); -plot_cvx = true; -show_results; -plot_cvx = false; - -% case 2: know lambda -lambda = 2.4; -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'foopsi', 'lambda', lambda); - -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); - -figure('name', 'FOOPSI, AR1, known:lambda, estimated: g', 'papersize', [15, 4]); -show_results; - -% case 3: know lambda, fit g -lambda = 2.4; -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'foopsi', 'lambda', lambda, ... - 'optimize_pars'); - -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); - -figure('name', 'MCMC, AR1'); -show_results; -%%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% diff --git a/deconvolveCa/examples/ar1_mcmc.m b/deconvolveCa/examples/ar1_mcmc.m deleted file mode 100644 index 426709f..0000000 --- a/deconvolveCa/examples/ar1_mcmc.m +++ /dev/null @@ -1,27 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 1: foopsi, AR1 model. This model is used when the sampling rate is low -g = 0.95; % AR coefficient -noise = .3; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 1; % number of trials -seed = 13; % seed for genrating random variables -[y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); - -% case 1: all parameters are known -lambda = 2.4; -params.p = 1; -params.B = 1; -[c_oasis, s_oasis] = deconvolveCa(y, 'mcmc', params); %#ok<*ASGLU> -[c_cvx, s_cvx] = foopsi(y, g, lambda); - -figure('name', 'FOOPSI, AR1, known: g, lambda', 'papersize', [15, 4]); -plot_cvx = true; -show_results; -plot_cvx = false; diff --git a/deconvolveCa/examples/ar1_thresholded_foopsi.m b/deconvolveCa/examples/ar1_thresholded_foopsi.m deleted file mode 100644 index 14fbb67..0000000 --- a/deconvolveCa/examples/ar1_thresholded_foopsi.m +++ /dev/null @@ -1,38 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 4: hard threshold, AR1 model -g = 0.95; % AR coefficient -noise = .3; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 1; % number of trials -seed = 13; % seed for genrating random variables -[y, true_c, true_s] = gen_data(g, noise, T, framerate, firerate, b, N, seed); - -% case 1: all parameters are known -smin = 0.5; -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', g, 'thresholded', 'smin', smin); %#ok<*ASGLU> - -figure('name', 'threshold, AR1, known: g, lambda, smin', 'papersize', [15, 4]); -show_results; - -% case 2: know smin -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', 'thresholded', 'smin', smin); - -fprintf('true gamma: %.3f\n', g); -fprintf('estimated gamma: %.3f\n', options.pars); - -figure('name', 'threshold, AR1, known:smin, estimated: g', 'papersize', [15, 4]); -show_results; - -% case 3: optimize the thershold, g, and the baseline -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar1', g, ... - 'thresholded', 'optimize_smin', 'optimize_pars', 'thresh_factor', 0.99); %#ok<*ASGLU> - -figure('name', 'threshold, AR1, known: g, sn, estimate: smin, g', 'papersize', [15, 4]); -show_results; \ No newline at end of file diff --git a/deconvolveCa/examples/ar2_foopsi.m b/deconvolveCa/examples/ar2_foopsi.m deleted file mode 100644 index d269914..0000000 --- a/deconvolveCa/examples/ar2_foopsi.m +++ /dev/null @@ -1,36 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 2: foopsi, AR2 model -g = [1.7, -0.712]; % AR coefficient -noise = 1; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 20; % number of trials -seed = 3; % seed for genrating random variables -[Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); -y = Y(1,:); -true_c = trueC(1,:); %#ok<*NASGU> -true_s = trueS(1,:); -% case 1: all parameters are known -lambda = 25; -[c_oasis, s_oasis] = deconvolveCa(y, 'ar2', g, 'foopsi', 'lambda', lambda); %#ok<*ASGLU> - -figure('name', 'FOOPSI, AR2, known: g, lambda', 'papersize', [15, 4]); -show_results; - -% case 2: know lambda -lambda = 2.5; -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'foopsi', 'lambda',... - lambda); -fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); -fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); - -figure('name', 'FOOPSI, AR2, known:lambda, estimated: g', 'papersize', [15, 4]); -show_results; - -%%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% diff --git a/deconvolveCa/examples/ar2_mcmc.m b/deconvolveCa/examples/ar2_mcmc.m deleted file mode 100644 index b920824..0000000 --- a/deconvolveCa/examples/ar2_mcmc.m +++ /dev/null @@ -1,26 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 2: foopsi, AR2 model -g = [1.7, -0.712]; % AR coefficient -noise = 1; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 20; % number of trials -seed = 3; % seed for genrating random variables -[Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); -y = Y(1,:); -true_c = trueC(1,:); %#ok<*NASGU> -true_s = trueS(1,:); -% case 1: all parameters are known -lambda = 25; -params.p = 2; -params.B = 300; -[c_oasis, s_oasis] = deconvolveCa(y, 'mcmc', params); %#ok<*ASGLU> - -figure('name', 'FOOPSI, AR2, known: g, lambda', 'papersize', [15, 4]); -show_results; diff --git a/deconvolveCa/examples/ar2_thresholded_foopsi.m b/deconvolveCa/examples/ar2_thresholded_foopsi.m deleted file mode 100644 index e3be1a6..0000000 --- a/deconvolveCa/examples/ar2_thresholded_foopsi.m +++ /dev/null @@ -1,54 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - - -%% threshold, AR2 model -g = [1.7, -0.712]; % AR coefficient -noise = 1; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 20; % number of trials -seed = 3; % seed for genrating random variables -[Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); -y = Y(1,:); -true_c = trueC(1,:); %#ok<*NASGU> -true_s = trueS(1,:); -% case 1: all parameters are known -smin = 0.5; -[c_oasis, s_oasis] = deconvolveCa(y, 'ar2', g, 'thresholded', 'smin', smin); %#ok<*ASGLU> -figure('name', 'threshold, AR2, known: g, smin', 'papersize', [15, 4]); -show_results; - -% case 2: know smin -smin = 0.5; -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'thresholded',... - 'smin', smin); -fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); -fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); - -figure('name', 'threshold, AR2, known:smin, estimated: g', 'papersize', [15, 4]); -show_results; - -%% case 3: know smin, update g -smin = 0.5; -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'thresholded',... - 'smin', smin, 'optimize_pars'); -fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); -fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); - -figure('name', 'threshold, AR2, known:smin, estimated: g', 'papersize', [15, 4]); -show_results; - -%% case 3: estimate smin -[c_oasis, s_oasis, options] = deconvolveCa(y, 'ar2', 'sn', noise, 'thresholded',... - 'optimize_smin','optimize_pars', 'thresh_factor', 1); -% fprintf('true gamma: %.3f\t %.3f\n', g(1), g(2)); -% fprintf('estimated gamma: %.3f\t %.3f\n', options.pars(1), options.pars(2)); -fprintf('estimated smin: %.3f\n', options.smin); -figure('name', 'threshold, AR2, known:smin, estimated: g', 'papersize', [15, 4]); -show_results; -%%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% diff --git a/deconvolveCa/examples/foopsi_kernel.m b/deconvolveCa/examples/foopsi_kernel.m deleted file mode 100644 index a59c334..0000000 --- a/deconvolveCa/examples/foopsi_kernel.m +++ /dev/null @@ -1,157 +0,0 @@ -function [c, s, b, g, active_set] = foopsi_oasisAR1(y, g, lam, optimize_b,... - optimize_g, decimate, maxIter) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g c_{t-1} >= 0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 1); -end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end - -%% optimize parameters -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks, active_set] = oasisAR1(y, g, lam); - - %% iteratively update parameters g - if optimize_g % update g - [solution, active_set, g, spks] = update_g(y, active_set,lam); - end -else - %% initialization - b = quantile(y, 0.15); - [solution, spks, active_set] = oasisAR1(y-b, g, lam); - - %% iteratively update parameters g and b - for m=1:maxIter - b = mean(y-solution); - if optimize_g % update g - g0 = g; - [solution, active_set, g, spks] = update_g(y-b, active_set,lam); - if abs(g-g0)/g0 < 1e-3 % g is converged - optimize_g = false; - end - else - break; - end - end -end -c = solution; -s = spks; -end -%update the AR coefficient: g -function [c, active_set, g, s] = update_g(y, active_set, lam) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% active_set: npools*4 matrix, previous active sets. -% lam: scalar, curret value of sparsity penalty parameter lambda. - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization - -len_active_set = size(active_set, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(active_set(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% find the optimal g and get the warm started active_set -g = fminbnd(@rss_g, 0, 1); -yp = y - lam*(1-g); -for m=1:len_active_set - tmp_h = exp(log(g)*(0:maxl)'); % response kernel - tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - li = active_set(m, 4); - ti = active_set(m, 3); - idx = ti:(ti+li-1); - active_set(m,1) = (yp(idx))'*tmp_h(1:li); - active_set(m,2) = tmp_hh(li); -end -[c,s,active_set] = oasisAR1(y, g, lam, [], active_set); - -%% nested functions - function rss = rss_g(g) - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - yp = y - lam*(1-g); % include the penalty term - for ii=1:len_active_set - li = active_set(ii, 4); - ti = active_set(ii, 3); - idx = ti:(ti+li-1); - tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end -end \ No newline at end of file diff --git a/deconvolveCa/examples/foopsi_onnls.m b/deconvolveCa/examples/foopsi_onnls.m deleted file mode 100644 index 4a3b45b..0000000 --- a/deconvolveCa/examples/foopsi_onnls.m +++ /dev/null @@ -1,190 +0,0 @@ -function [c, s, b, g, active_set] = foopsi_exp2(y, taus, lam, optimize_b,... - optimize_kernel, decimate, maxIter, shift, win, tol, mask, smin) - -%% Infer the most likely discretized spike train for the model c = conv(s, kernel) -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to c = conv(s, kernel)>= 0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% shift: integer scalar, number of frames by which to shift window from on run of -% NNLS to the next, default-100 -% win: integer acalar, window size -% tol: scalar, tolerance parameters -% maxIter: scalar, maximum number of iterations before termination -% mask: T * 1 boolean vector, restrict potential spike times -% smin: scalar, minimum spike size - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% taus: 1*2 vector, [tau_d, tau_r] - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('shift', 'var') || isempty(shift) - shift = 100; -end -if ~exist('win', 'var') || isempty(win) - win = 200; -end - -if ~exist('tol', 'var') || isempty(tol) - tol = 1e-9; -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = []; -end -if ~exist('mask', 'var') || isempty(mask) - mask = true(T,1); -end -if ~exist('smin', 'var') || isempty(smin) - smin = 0; -end - -if ~exist('kernel', 'var') || isempty(kernel) - g = estimate_time_constant(y, 2); - taus = ar2exp(g); - kernel = exp2kernel(taus, win); -end - -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end - -%% optimize parameters -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks] = onnls(y, kernel, lam, shift, win, tol, maxIter, mask, smin); - - %% iteratively update parameters g - if optimize_g % update g - pars.vals = taus; - [pars, s] = update_tau(y, spks, pars, nspk); - end -else - disp('to be done'); -% %% initialization -% b = quantile(y, 0.15); -% [solution, spks, active_set] = oasisAR1(y-b, g, lam); -% -% %% iteratively update parameters g and b -% for m=1:maxIter -% b = mean(y-solution); -% if optimize_g % update g -% g0 = g; -% [solution, active_set, g, spks] = update_g(y-b, active_set,lam); -% if abs(g-g0)/g0 < 1e-3 % g is converged -% optimize_g = false; -% end -% else -% break; -% end -% end -end -c = solution; -s = spks; -end - - -%update the AR coefficient: g -% function [c, active_set, g, s] = update_g(y, active_set, lam) -% %% inputs: -% % y: T*1 vector, One dimensional array containing the fluorescence intensities -% %withone entry per time-bin. -% % active_set: npools*4 matrix, previous active sets. -% % lam: scalar, curret value of sparsity penalty parameter lambda. -% -% %% outputs -% % c: T*1 vector -% % s: T*1 vector, spike train -% % active_set: npool x 4 matrix, active sets -% % g: scalar -% -% %% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% % ported from the Python implementation from Johannes Friedrich -% -% %% References -% % Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging -% -% %% initialization -% -% len_active_set = size(active_set, 1); %number of active sets -% y = reshape(y,[],1); % fluorescence data -% maxl = max(active_set(:, 4)); % maximum ISI -% c = zeros(size(y)); % the optimal denoised trace -% -% %% find the optimal g and get the warm started active_set -% g = fminbnd(@rss_g, 0, 1); -% yp = y - lam*(1-g); -% for m=1:len_active_set -% tmp_h = exp(log(g)*(0:maxl)'); % response kernel -% tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) -% li = active_set(m, 4); -% ti = active_set(m, 3); -% idx = ti:(ti+li-1); -% active_set(m,1) = (yp(idx))'*tmp_h(1:li); -% active_set(m,2) = tmp_hh(li); -% end -% [c,s,active_set] = oasisAR1(y, g, lam, [], active_set); -% -% %% nested functions -% function rss = rss_g(g) -% h = exp(log(g)*(0:maxl)'); % response kernel -% hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) -% yp = y - lam*(1-g); % include the penalty term -% for ii=1:len_active_set -% li = active_set(ii, 4); -% ti = active_set(ii, 3); -% idx = ti:(ti+li-1); -% tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); -% c(idx) = tmp_v*h(1:li); -% end -% res = y-c; -% rss = res'*res; % residual sum of squares -% end -% end \ No newline at end of file diff --git a/deconvolveCa/examples/kernel_foopsi.m b/deconvolveCa/examples/kernel_foopsi.m deleted file mode 100644 index 4f8c0cf..0000000 --- a/deconvolveCa/examples/kernel_foopsi.m +++ /dev/null @@ -1,63 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - -%% example 3: foopsi, convolution kernel -g = [1.7, -0.712]; % AR coefficient -noise = 1; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 20; % number of trials -seed = 3; % seed for genrating random variables -[Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); -y = Y(1,:); -true_c = trueC(1,:); %#ok<*NASGU> -true_s = trueS(1,:); -taus = ar2exp(g); -w = 200; -taus = ar2exp(g); -ht = exp2kernel(taus, w); -% case 1: use the difference of two exponential functions to construct a -% kernel -lambda = 25; -[c_oasis, s_oasis] = deconvolveCa(y, 'exp2', taus, 'foopsi', 'lambda', lambda, ... - 'shift', 100, 'window', 200); %#ok<*ASGLU> - -figure('name', 'FOOPSI, exp2, known: g, lambda', 'papersize', [15, 4]); -show_results; - -% case 2: use the kernel directly -lambda = 25; -[c_oasis, s_oasis] = deconvolveCa(y, 'kernel', ht, 'foopsi', 'lambda', ... - lambda, 'shift', 100, 'window', 200); %#ok<*ASGLU> - -figure('name', 'FOOPSI, kernel, known: g, lambda', 'papersize', [15, 4]); -show_results; - - -%% case 3: estimate the time constants -lambda = 0; -taus = ar2exp(g); -[c_oasis, s_oasis, options] = deconvolveCa(y, 'exp2', 'foopsi', 'lambda', lambda, ... - 'shift', 100, 'window', 200, 'smin', 0.5); %#ok<*ASGLU> - -figure('name', 'FOOPSI, exp2, known: g, lambda', 'papersize', [15, 4]); -show_results; - - - - - - - - - - - - - - - diff --git a/deconvolveCa/examples/kernel_thresholded_foopsi.m b/deconvolveCa/examples/kernel_thresholded_foopsi.m deleted file mode 100644 index 247eb96..0000000 --- a/deconvolveCa/examples/kernel_thresholded_foopsi.m +++ /dev/null @@ -1,39 +0,0 @@ -%% test modulate for all oasis functions. -col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],... - [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors -plot_cvx = false; - - -%% threshold foopsi, convolution kernel -g = [1.7, -0.712]; % AR coefficient -noise = 1; -T = 3000; -framerate = 30; -firerate = 0.5; -b = 0; % baseline -N = 20; % number of trials -seed = 3; % seed for genrating random variables -[Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed); -y = Y(1,:); -true_c = trueC(1,:); %#ok<*NASGU> -true_s = trueS(1,:); -temp = roots([1, -g(1), -g(2)]); -d = max(temp); -r = min(temp); -w = 200; -ht = (exp(log(d)*(1:w)) - exp(log(r)*(1:w))) / (d-r); % convolution kernel - -% case 1: all parameters are known, the kernel is the sum of two -% exponential functions -smin = 0.5; -pars = [d, r]; -[c_oasis, s_oasis] = deconvolveCa(y, 'exp2', pars, 'thresholded', 'smin', smin); %#ok<*ASGLU> -figure('name', 'threshold, exp2, known: taur, taud, smin', 'papersize', [15, 4]); -show_results; - -% case 1: all parameters are known -smin = 0.5; -[c_oasis, s_oasis] = deconvolveCa(y, 'kernel', ht, 'thresholded', 'smin', smin); %#ok<*ASGLU> -figure('name', 'threshold, kernel, known: kernel, smin', 'papersize', [15, 4]); -show_results; -%%%%%%%%%%%%%% END %%%%%%%%%%%%%%%%%% diff --git a/deconvolveCa/examples/show_results.m b/deconvolveCa/examples/show_results.m deleted file mode 100644 index 7b9f3af..0000000 --- a/deconvolveCa/examples/show_results.m +++ /dev/null @@ -1,39 +0,0 @@ -init_fig; - -% c -axes('position', [.05, .57, .95, .37]); -hold on; -plot(y, 'color', col{8}/255); -alpha(.7); -plot(true_c, 'color', col{3}/255, 'linewidth', 1.5); -plot(c_oasis, '-.', 'color', col{5}/255); -if plot_cvx && exist('c_cvx', 'var') - plot(c_cvx, '-.', 'color', col{7}/255); -end -axis tight; -xlim([0, 2000]); -set(gca, 'xtick', [0, 25, 50, 75]*30); -set(gca, 'xticklabel', []); -set(gca, 'ytick', 0:2); -ylabel('Fluor.'); -box off; -if plot_cvx - legend('Data', 'Truth', 'OASIS', 'CVX', 'location', 'northeast', 'orientation', 'horizental'); -else - legend('Data', 'Truth', 'OASIS', 'location', 'northeast', 'orientation', 'horizental'); -end -% s -axes('position', [.05, .18, .95, .37]); -hold on; -plot(true_s, 'color', col{3}/255, 'linewidth', 1.5); -plot(s_oasis, '-.', 'color', col{5}/255); -if plot_cvx && exist('s_cvx', 'var') - plot(s_cvx, '-.', 'color', col{7}/255); -end -axis tight; -xlim([0, 2000]); -set(gca, 'xtick', [0, 25, 50, 75]*30); -set(gca, 'xticklabel', get(gca, 'xtick')/30); -set(gca, 'ytick', [0,1]); -xlabel('Time [s]'); -ylabel('Activity.'); \ No newline at end of file diff --git a/deconvolveCa/examples/test_all.m b/deconvolveCa/examples/test_all.m deleted file mode 100644 index a1c5de5..0000000 --- a/deconvolveCa/examples/test_all.m +++ /dev/null @@ -1,85 +0,0 @@ -%% FOOPSI (all done ) -% AR1 -fprintf('AR1, FOOPSI...'); -try - ar1_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - -% AR2 -fprintf('\nAR2, FOOPSI...'); -try - ar2_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - -% kernel -fprintf('\nkernel, FOOPSI...'); -try - kernel_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - - -%% Constrained FOOPSI (need AR2, kernel ) -% AR1 -fprintf('\nAR1, constrained FOOPSI...'); -try - ar1_constrained_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - -%% Thresholded FOOPSI (all done) -% AR1 -fprintf('\nAR1, thresholded FOOPSI...'); -try - ar1_thresholded_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - -% AR2 -fprintf('\nAR2, thresholded FOOPSI... '); -try - ar2_thresholded_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - - -% AR2 -fprintf('\nkernel, thresholded FOOPSI... '); -try - kernel_thresholded_foopsi; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end - -%% MCMC -% AR1 -fprintf('\nAR1, MCMC...'); -try - ar1_mcmc; - fprintf('success!\n\n'); - drawnow; -catch - fprintf('fail!\n\n'); -end diff --git a/deconvolveCa/functions/GetSn.m b/deconvolveCa/functions/GetSn.m deleted file mode 100644 index ea4850c..0000000 --- a/deconvolveCa/functions/GetSn.m +++ /dev/null @@ -1,50 +0,0 @@ -function sn = GetSn(Y, range_ff, method) -%% Estimate noise standard deviation - -%% inputs: -% Y: N X T matrix, fluorescence trace -% range_ff : 1 x 2 vector, nonnegative, max value <= 0.5, range of frequency (x Nyquist rate) over which the spectrum is averaged -% method: string, method of averaging: Mean, median, exponentiated mean of logvalues (default) - -%% outputs: -% sn: scalar, std of the noise - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% adapted from the MATLAB implemention by Eftychios Pnevmatikakis and the -% Python implementation from Johannes Friedrich - -%% References -% Pnevmatikakis E. et.al., Neuron 2016, Simultaneous Denoising, Deconvolution, and Demixing of Calcium Imaging Data - -%% input arguments -if ~exist('range_ff', 'var') || isempty(range_ff) - range_ff = [.25, .5]; -end -if ~exist('method', 'var') || isempty(method) - method = 'logmexp'; -end -if any(size(Y)==1) - Y = reshape(Y, [], 1); -else - Y = Y'; -end - -%% estimate the noise -[psdx, ff] = pwelch(double(Y), [],[],[], 1); -indf = and(ff>=range_ff(1), ff<=range_ff(2)); -switch method - case 'mean' - sn=sqrt(mean(psdx(indf, :)/2)); - case 'median' - sn=sqrt(median(psdx(indf,:)/2)); - case 'logmexp' - sn = sqrt(exp(mean(log(psdx(indf,:)/2)))); - otherwise - fprintf('wrong method! use logmexp instead.\n'); - sn = sqrt(exp(mean(log(psdx(indf,:)/2)))); -end -sn = sn'; - - - - diff --git a/deconvolveCa/functions/ar2exp.m b/deconvolveCa/functions/ar2exp.m deleted file mode 100644 index c7afbb1..0000000 --- a/deconvolveCa/functions/ar2exp.m +++ /dev/null @@ -1,13 +0,0 @@ -function tau_dr = ar2exp(g) -%% get parameters of the convolution kernel for AR2 process -if length(g)==1 - g(2) = 0; -end - -temp = roots([1, -g(1), -g(2)]); -d = max(temp); -r = min(temp); -tau_d = -1/log(d); -tau_r = -1/log(r); - -tau_dr = [tau_d, tau_r]; \ No newline at end of file diff --git a/deconvolveCa/functions/choose_smin.m b/deconvolveCa/functions/choose_smin.m deleted file mode 100644 index 40a6576..0000000 --- a/deconvolveCa/functions/choose_smin.m +++ /dev/null @@ -1,42 +0,0 @@ -function smin = choose_smin(kernel,sn,prob) -%% Choose minimal spike spike to enforce sparsity constraint in spike inference -% The function chooses a regularization weight for sparse deconvolution -% with a given kernel and noise level. The weight of the regularizer -% is chosen such that noise alone cannot lead to a non-zero solution is -% at least prob. - -% Inputs: -% kernel: deconvolution kernel -% if length(kernel) == 1 or length(kernel) == 2, then kernel -% is treated as a set of discrete time constants g. Otherwise, -% it is treated as the actual vector. -% sn: noise level -% prob: probability of zero solution (deafult: 0.99) - -% Output: -% smin: minimal spike size - -% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -% modified from choose_lambda.m Eftychios A. Pnevmatikakis, 2016, Simons Foundation -% based on ideas and discussions with J. Tubiana and G. Debregeas, -% Laboratorie Jean Parrin, UPMC, France - -% Reference for this approach: -% Selesnick, I. (2012). Sparse deconvolution (an MM algorithm) - -%% - -if nargin < 3 || isempty(prob) - prob = 0.99999; -end - -if nargin < 2 || isempty(sn) - sn = 1; - warning('Noise value not provided. Using sn = 1...') -end - -if length(kernel) <= 2 - kernel = filter(1,[1,-kernel(:)'],[1,zeros(1,999)]); -end - -smin = sn/norm(kernel)*norminv(prob); \ No newline at end of file diff --git a/deconvolveCa/functions/constrained_foopsi_cvx.m b/deconvolveCa/functions/constrained_foopsi_cvx.m deleted file mode 100644 index 7e0d163..0000000 --- a/deconvolveCa/functions/constrained_foopsi_cvx.m +++ /dev/null @@ -1,56 +0,0 @@ -function [c, s] = constrained_foopsi_cvx(y, g, sn, solver) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min |s|_1 subject to s=G*c >=0 and |y-c|_2^2=\sigma*T^2 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% sn: scalar, noise standard deviation -% solver: string, optimization solver - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging -% Pnevmatikakis E. et.al., Neuron 2016, Simultaneous Denoising, Deconvolution, and Demixing of Calcium Imaging Data - -%% initialization -y = reshape(y, [], 1); -T = length(y); -if ~exist('g', 'var') || isempty(g); g = estimate_time_constant(y, 1); end -if ~exist('sn', 'var') || isempty(sn); sn = GetSn(y); end -if ~exist('solver', 'var') || isempty(solver); solver = 'SDPT3'; end - -% construct the deconvolution matrix (s=G*c) -len_g = length(g); -g = reshape(g, 1, []); -indc = bsxfun(@minus, (1:T)', 0:len_g); -indr = repmat((1:T)', [1, len_g+1]); -v = ones(T,1)*[1,-g]; -ind = (indc>0); -G = sparse(indr(ind), indc(ind), v(ind), T, T); - -%% run optimization -% cvx_solver(solver); -cvx_begin quiet - variable c(T) - minimize(norm(c,1)) - subject to - G*c >=0; - norm(y-c,2) <= sn*sqrt(T); -cvx_end - -s = reshape(G*c, 1, []); -s(1) = 0; -c = reshape(c,1, []); - - - diff --git a/deconvolveCa/functions/estimate_baseline_noise.m b/deconvolveCa/functions/estimate_baseline_noise.m deleted file mode 100644 index 62321e3..0000000 --- a/deconvolveCa/functions/estimate_baseline_noise.m +++ /dev/null @@ -1,35 +0,0 @@ -function [b, sn] = estimate_baseline_noise(y, bmin) -%% estimate the baseline and noise level for single calcium trace -%% inputs: -% y: T*1 vector, calcium trace -% thr: scalar, threshold for choosing points for fitting a gaussian -% distribution. -% bmin: scalar, minimum value of the baseline, default(-inf) -%% outputs: -% b: scalar, baseline -% sn: scalar, sigma of the noise -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% input arguments -if ~exist('bmin', 'var') || isempty(bmin) - bmin = -inf; -end - -%% create the histogram for fitting -temp = quantile(y, 0:0.1:1); -dbin = max(min(diff(temp))/3, (max(temp)-min(temp))/1000); -bins = temp(1):dbin:temp(end); -nums = hist(y, bins); - -%% fit a gaussian distribution: nums = A * exp(-(bins-b)/(2*sig^2)) -if isempty(bins) - b = mean(y); - sn = 0; - return; -end -[b, sn] = fit_gauss1(bins, nums, 0.3, 3); - -if b1) && p < 5 -% warning('No stable AR(%i) model found. Checking for AR(%i) model \n',p, p+1); - p = p + 1; - g = estimate_time_constant(y,p,sn,lags); -end -if p == 5 - g = 0; -end - -% re-adjust time constant values -rg = roots([1;-g(:)]); -if ~isreal(rg); rg = real(rg) + .001*randn(size(rg)); end -rg(rg>1) = 0.95 + 0.001*randn(size(rg(rg>1))); -rg(rg<0) = 0.15 + 0.001*randn(size(rg(rg<0))); -pg = poly(fudge_factor*rg); -g = -pg(2:end); - diff --git a/deconvolveCa/functions/exp2ar.m b/deconvolveCa/functions/exp2ar.m deleted file mode 100644 index b2ea5fc..0000000 --- a/deconvolveCa/functions/exp2ar.m +++ /dev/null @@ -1,8 +0,0 @@ -function g = exp2ar(tau_dr) -%% convert a convolution function to an AR(2) model - -d = exp(-1/tau_dr(1)); -r = exp(-1/tau_dr(2)); - -g(1) = d+r; -g(2) = -d*r; \ No newline at end of file diff --git a/deconvolveCa/functions/exp2kernel.m b/deconvolveCa/functions/exp2kernel.m deleted file mode 100644 index 039f473..0000000 --- a/deconvolveCa/functions/exp2kernel.m +++ /dev/null @@ -1,17 +0,0 @@ -function ht = exp2kernel(taus, nmax) -%% create the convolution kernel given tau_rise and tau_decay - -%% inputs: -% taus: 1*2 vector, [tau_decay tau_rise] -% nmax: scalar, length of the kernel - -%% outputs: -% ht: nmax*1 kernel, convolution kernel - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -t = (1:nmax)'; -d = exp(-1./taus(1)); -r = exp(-1./taus(2)); -ht = (exp(log(d)*t) - exp(log(r)*t) ) / (d - r); -ht = ht/sum(ht); \ No newline at end of file diff --git a/deconvolveCa/functions/fit_gauss1.m b/deconvolveCa/functions/fit_gauss1.m deleted file mode 100644 index 199251f..0000000 --- a/deconvolveCa/functions/fit_gauss1.m +++ /dev/null @@ -1,83 +0,0 @@ -function [mu, sig, A] = fit_gauss1(x, y, thr, maxIter, mu_fix) -%% fit a gaussin curve given the data (x, y): y = A*exp(-(x-mu)^2/2/sig^2) - -%% inputs: -% x: T*1 vector -% y: T*1 vector -% thr: scalar, threshold for selecting points for fitting -% maxIter: scalar, maximum iteration -% mu_fix: boolean, fix the center to be 0 or not -%% outputs: -% mu: scalar, center of the peak -% sig: scalar, gaussian width -% A: scalar, amplitude of the gaussian curve - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -%% Reference: -% A Simple Algorithm for Fitting a Gaussian Function , Hongwei Guo, 2011 - -%% input arguments -x = reshape(x, [], 1); -y = reshape(y, [], 1); -T = length(y); - -if ~exist('thr', 'var') || isempty(thr) - thr = 0.1; -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 5; -end -if ~exist('mu_fix', 'var') || isempty(mu_fix) - mu_fix = false; -end -ind = (y>max(y)*thr); -x = x(ind); -y = y(ind); - -x2 = x.^2; -x3 = x.^3; -x4 = x.^4; -y2 = y.^2; -logy = log(y); -y2logy = y2.*logy; -vec1 = ones(1, length(y)); - -warning('off','MATLAB:nearlySingularMatrix'); -warning('off','MATLAB:SingularMatrix'); -%% fit the curve -if mu_fix % fix the mu to be 0 - for miter=1:maxIter - M = [vec1*y2, x2'*y2; ... - x2'*y2, x4'*y2]; - b = [vec1*y2logy; x2'*y2logy]; - p = M\b; - - logy = p(1)*vec1' + p(2)*x2; - y = exp(logy); - y2 = y.^2; - y2logy = y2.*logy; - end - - mu= 0; - sig = sqrt(-0.5/p(2)); - A = exp(p(1)); -else - for miter=1:maxIter - M = [vec1*y2, x'*y2, x2'*y2; ... - x'*y2, x2'*y2, x3'*y2; ... - x2'*y2, x3'*y2, x4'*y2]; - b = [vec1*y2logy; x'*y2logy; x2'*y2logy]; - p = (M)\b; - - logy = p(1)*vec1' + p(2)*x + p(3)*x2; - y = exp(logy); - y2 = y.^2; - y2logy = y2.*logy; - end - mu= -p(2)/2/p(3); - sig = abs(sqrt(-0.5/p(3))); - A = exp(p(1)-0.25*p(2)^2/p(3)); -end - -warning('on','MATLAB:nearlySingularMatrix'); -warning('on','MATLAB:SingularMatrix'); diff --git a/deconvolveCa/functions/foopsi.m b/deconvolveCa/functions/foopsi.m deleted file mode 100644 index 2e46a79..0000000 --- a/deconvolveCa/functions/foopsi.m +++ /dev/null @@ -1,59 +0,0 @@ -function [c, s] = foopsi(y, g, lam, solver) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g c_{t-1} >= 0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter lambda. -% solver: string, optimization solver - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization -y = reshape(y, [], 1); -T = length(y); -if ~exist('g', 'var') || isempty(g); g = estimate_time_constant(y, 2); end - - -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('solver', 'var') || isempty(smin); solver = 'SDPT3'; end - -% construct the deconvolution matrix (s=G*c) -len_g = length(g); -g = reshape(g, 1, []); -indc = bsxfun(@minus, (1:T)', 0:len_g); -indr = repmat((1:T)', [1, len_g+1]); -v = ones(T,1)*[1,-g]; -ind = (indc>0); -G = sparse(indr(ind), indc(ind), v(ind), T, T); - -%% run optimization -% cvx_solver(solver); - -cvx_begin quiet -variable c(T) -minimize(0.5*(c-y)'*(c-y) + lam*(1-sum(g))*norm(c,1)) -subject to -G*c >=0; -cvx_end - -s = reshape(G*c, 1, []); -s(1) = 0; -c = reshape(c,1, []); - - - - - diff --git a/deconvolveCa/functions/gen_data.m b/deconvolveCa/functions/gen_data.m deleted file mode 100644 index dc37c3d..0000000 --- a/deconvolveCa/functions/gen_data.m +++ /dev/null @@ -1,62 +0,0 @@ -function [Y, truth, trueSpikes] = gen_data(gam, noise, T, framerate, ... - firerate, b, N, seed) - -%% input arguments -if ~exist('gam', 'var') || isempty(gam) - gam = .95; -end -if ~exist('noise', 'var') || isempty(noise) - noise = .3; -end -if ~exist('T', 'var') || isempty(T) - T = 3000; -end -if ~exist('framerate', 'var') || isempty(framerate) - framerate = 30; -end -if ~exist('firerate', 'var') || isempty(firerate) - firerate = .5; -end -if ~exist('b', 'var') || isempty(b) - b = 0; -end -if ~exist('N', 'var') || isempty(N) - N = 20; -end -if ~exist('seed', 'var') || isempty(seed) - seed = 13; -end - -%% run simulation -rng(seed); -trueSpikes = (rand(N, T) < firerate/framerate); -truth = double(trueSpikes); -p = length(gam); -gam = [flipud(reshape(gam, [], 1)); 1]; - -for t=(p+1):T - truth(:, t) = truth(:, (t-p):t) * gam; -end - -Y = b + truth + noise * randn(N, T); - - - - - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/functions/gen_sinusoidal_data.m b/deconvolveCa/functions/gen_sinusoidal_data.m deleted file mode 100644 index fc27cf2..0000000 --- a/deconvolveCa/functions/gen_sinusoidal_data.m +++ /dev/null @@ -1,63 +0,0 @@ -function [Y, truth, trueSpikes] = gen_sinusoidal_data(gam, noise, T, framerate, ... - firerate, b, N, seed) - -%% input arguments -if ~exist('gam', 'var') || isempty(gam) - gam = .95; -end -if ~exist('noise', 'var') || isempty(noise) - noise = .3; -end -if ~exist('T', 'var') || isempty(T) - T = 3000; -end -if ~exist('framerate', 'var') || isempty(framerate) - framerate = 30; -end -if ~exist('firerate', 'var') || isempty(firerate) - firerate = .5; -end -if ~exist('b', 'var') || isempty(b) - b = 0; -end -if ~exist('N', 'var') || isempty(N) - N = 20; -end -if ~exist('seed', 'var') || isempty(seed) - seed = 13; -end - -%% run simulation -rng(seed); -trueSpikes = bsxfun(@lt, rand(N, T),... - 4 * firerate/framerate * sin((1:T)/50).^3); -truth = double(trueSpikes); -p = length(gam); -gam = [flipud(reshape(gam, [], 1)); 1]; - -for t=(p+1):T - truth(:, t) = truth(:, (t-p):t) * gam; -end - -Y = b + truth + noise * randn(N, T); - - - - - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/functions/init_fig.m b/deconvolveCa/functions/init_fig.m deleted file mode 100644 index 018003b..0000000 --- a/deconvolveCa/functions/init_fig.m +++ /dev/null @@ -1,5 +0,0 @@ -set(gcf, 'color', 'w', ... - 'defaultAxesFontSize', 20, ...) - 'defaultlinelinewidth',2, ... - 'position', [0, 0, 100*get(gcf, 'papersize')], ... - 'paperposition', [0, 0, get(gcf, 'papersize')]) diff --git a/deconvolveCa/functions/max_ht.m b/deconvolveCa/functions/max_ht.m deleted file mode 100644 index 0aeb3f9..0000000 --- a/deconvolveCa/functions/max_ht.m +++ /dev/null @@ -1,28 +0,0 @@ -function vmax = max_ht(pars1, pars2) -%% Get the maximum response value following one calcium transient -%% inputs: -% pars1: if nargin<2, pars1 is the AR coefficients; else pars1 is the -% decay time constant -% pars2: the rising time constant -%% outputs: -% ht: nmax*1 kernel, convolution kernel - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -if nargin<2 - if length(pars1) ==1 - % AR1 model - vmax = 1; - return; - else - % AR2 model - taus = ar2exp(pars1); - end -else - taus = [pars1, pars2]; -end - -t = (1:ceil(taus(1)*2))'; -d = exp(-1./taus(1)); -r = exp(-1./taus(2)); -ht = (exp(log(d)*t) - exp(log(r)*t) ) / (d - r); -vmax = max(ht); \ No newline at end of file diff --git a/deconvolveCa/oasis/choose_lambda.m b/deconvolveCa/oasis/choose_lambda.m deleted file mode 100644 index dede18a..0000000 --- a/deconvolveCa/oasis/choose_lambda.m +++ /dev/null @@ -1,41 +0,0 @@ -function lam = choose_lambda(kernel,sn,prob) -%% Choose regularizer weight for sparse deconvolution -% The function chooses a regularization weight for sparse deconvolution -% with a given kernel and noise level. The weight of the regularizer -% is chosen such that noise alone cannot lead to a non-zero solution is -% at least prob. - -% Inputs: -% kernel: deconvolution kernel -% if length(kernel) == 1 or length(kernel) == 2, then kernel -% is treated as a set of discrete time constants g. Otherwise, -% it is treated as the actual vector. -% sn: noise level -% prob: probability of zero solution (deafult: 0.99) - -% Output: -% lam: regularization weight - -% Author: Eftychios A. Pnevmatikakis, 2016, Simons Foundation -% based on ideas and discussions with J. Tubiana and G. Debregeas, -% Laboratorie Jean Parrin, UPMC, France - -% Reference for this approach: -% Selesnick, I. (2012). Sparse deconvolution (an MM algorithm) - -%% - -if nargin < 3 || isempty(prob) - prob = 0.99; -end - -if nargin < 2 || isempty(sn) - sn = 1; - warning('Noise value not provided. Using sn = 1...') -end - -if length(kernel) <= 2 - kernel = filter(1,[1,-kernel(:)'],[1,zeros(1,999)]); -end - -lam = sn*norm(kernel)*norminv(prob); \ No newline at end of file diff --git a/deconvolveCa/oasis/constrained_oasisAR1.m b/deconvolveCa/oasis/constrained_oasisAR1.m deleted file mode 100644 index ab4f72f..0000000 --- a/deconvolveCa/oasis/constrained_oasisAR1.m +++ /dev/null @@ -1,250 +0,0 @@ -function [c, s, b, g, lam, active_set] = constrained_oasisAR1(y, g, sn, optimize_b,... - optimize_g, decimate, maxIter) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g c_{t-1} >=s_min or =0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% sn: scalar, standard deviation of the noise distribution -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% lam: scalar, sparsity penalty parameter -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 1); -end -if ~exist('sn', 'var') || isempty(sn) - sn = GetSn(y); -end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end - -thresh = sn * sn * T; -lam = 0; - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end -g_converged = false; - -%% optimize parameters -tol = 1e-4; -% flag_lam = true; -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks, active_set] = oasisAR1(y, g, lam); - - %% iteratively update parameters lambda & g - for miter=1:maxIter - % update g - if and(optimize_g, ~g_converged); - g0 = g; - [solution, active_set, g, spks] = update_g(y, active_set,lam); - if abs(g-g0)/g0 < 1e-3 % g is converged - g_converged = true; - end - end - res = y - solution; - RSS = res' * res; - len_active_set = size(active_set, 1); - if RSS>thresh % constrained form has been found, stop - break; - else - % update lam - update_phi; - lam = lam + dphi; - end - end -else - %% initialization - b = quantile(y, 0.15); - [solution, spks, active_set] = oasisAR1(y-b, g, lam); - update_lam_b; - - %% optimize the baseline b and dependends on the optimized g too - g_converged = false; - for miter=1:maxIter - res = y - solution - b; - RSS = res' * res; - len_active_set = size(active_set,1); - - if or(abs(RSS-thresh) < tol, sum(solution)<1e-9) - break; - else - %% update b & lamba - update_phi(); - update_lam_b(); - % update b and g - % update b and g - if and(optimize_g, ~g_converged); - g0 = g; - [solution, active_set, g, spks] = update_g(y-b, active_set,lam); - if abs(g-g0)/g0 < 1e-4; - g_converged = true; - end - end - - end - end - -end -c = solution; -s = spks; - -%% nested functions - function update_phi() % estimate dphi to match the thresholded RSS - zeta = zeros(size(solution)); - maxl = max(active_set(:, 4)); - h = g.^(0:maxl); - for ii=1:len_active_set - ti = active_set(ii, 3); - li = active_set(ii, 4); - idx = 0:(li-1); - if ii1e-9 - flag_phi = false; - return; - else - flag_phi = true; - end - active_set(:,1) = active_set(:,1) - dphi*(1-g.^active_set(:,4)); - [solution, spks, active_set] = oasisAR1([], g, lam, [], active_set); - end - - function update_lam_b() % estimate lambda & b - db = mean(y-solution) - b; - b = b + db; - dlam = -db/(1-g); - - lam = lam + dlam; - % correct the last pool - active_set(end,1) = active_set(end,1) - lam*g^(active_set(end,4)); - ti = active_set(end,3); li = active_set(end,4); idx = 0:(li-1); - solution(ti+idx) = max(0, active_set(end,1)/active_set(end,2)) * (g.^idx); - end - -end -%update the AR coefficient: g -function [c, active_set, g, s] = update_g(y, active_set, lam) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% active_set: npools*4 matrix, previous active sets. -% lam: scalar, curret value of sparsity penalty parameter lambda. - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization - -len_active_set = size(active_set, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(active_set(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% find the optimal g and get the warm started active_set -g = fminbnd(@rss_g, 0, 1); -yp = y - lam*(1-g); -for m=1:len_active_set - tmp_h = exp(log(g)*(0:maxl)'); % response kernel - tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - li = active_set(m, 4); - ti = active_set(m, 3); - idx = ti:(ti+li-1); - active_set(m,1) = (yp(idx))'*tmp_h(1:li); - active_set(m,2) = tmp_hh(li); -end -[c,s,active_set] = oasisAR1(y, g, lam, [], active_set); - -%% nested functions - function rss = rss_g(g) - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - yp = y - lam*(1-g); % include the penalty term - for ii=1:len_active_set - li = active_set(ii, 4); - ti = active_set(ii, 3); - idx = ti:(ti+li-1); - tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end -end \ No newline at end of file diff --git a/deconvolveCa/oasis/constrained_oasisAR2.m b/deconvolveCa/oasis/constrained_oasisAR2.m deleted file mode 100644 index 99a013e..0000000 --- a/deconvolveCa/oasis/constrained_oasisAR2.m +++ /dev/null @@ -1,252 +0,0 @@ -function [c, s, b, g, lam, active_set] = constrained_oasisAR2(y, g, sn, optimize_b,... - optimize_g, decimate, maxIter) -%% Infer the most likely discretized spike train underlying an AR(2) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min lam |s|_1 -% subject to |y-c|_2^2 <= sn^2*T - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: 2 x 1 vector, Parameter of the AR(2) process that models the fluorescence ... -%impulse response. -% sn: scalar, standard deviation of the noise distribution -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% lam: scalar, sparsity penalty parameter -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 2); -end -if ~exist('sn', 'var') || isempty(sn) - sn = GetSn(y); -end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end - -thresh = sn * sn * T; -lam = 0; - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end -g_converged = false; - -%% optimize parameters -tol = 1e-4; -flag_lam = true; -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks, active_set] = oasisAR2(y, g, lam); - - %% iteratively update parameters lambda & g - for miter=1:maxIter - res = y - solution; - RSS = res' * res; - len_active_set = size(active_set, 1); - if or(abs(RSS-thresh) < tol, ~flag_lam) % constrained form has been found, stop - break; - else - % update lam - update_phi; - lam = lam + dphi; - - % update g - if and(optimize_g, ~g_converged); - g0 = g; - [solution, active_set, g, spks] = update_g(y, active_set,lam); - if abs(g-g0)/g0 < 1e-3 % g is converged - g_converged = true; - end - end - end - end -else - %% initialization - b = quantile(y, 0.15); - [solution, spks, active_set] = oasisAR2(y-b, g, lam); - update_lam_b; - - %% optimize the baseline b and dependends on the optimized g too - g_converged = false; - for miter=1:maxIter - res = y - solution - b; - RSS = res' * res; - len_active_set = size(active_set,1); - - if or(abs(RSS-thresh) < tol, sum(solution)<1e-9) - break; - else - %% update b & lamba - update_phi(); - update_lam_b(); - % update b and g - % update b and g - if and(optimize_g, ~g_converged); - g0 = g; - [solution, active_set, g, spks] = update_g(y-b, active_set,lam); - if abs(g-g0)/g0 < 1e-4; - g_converged = true; - end - end - - end - end - -end -c = solution; -s = spks; - -%% nested functions - function update_phi() % estimate dphi to match the thresholded RSS - zeta = zeros(size(solution)); - maxl = max(active_set(:, 4)); - h = g.^(0:maxl); - for ii=1:len_active_set - ti = active_set(ii, 3); - li = active_set(ii, 4); - idx = 0:(li-1); - if ii1e-9 - flag_phi = false; - return; - else - flag_phi = true; - end - active_set(:,1) = active_set(:,1) - dphi*(1-g.^active_set(:,4)); - [solution, spks, active_set] = oasisAR2([], g, lam, [], active_set); - end - - function update_lam_b() % estimate lambda & b - db = mean(y-solution) - b; - b = b + db; - dlam = -db/(1-g); - - lam = lam + dlam; - % correct the last pool - active_set(end,1) = active_set(end,1) - lam*g^(active_set(end,4)); - ti = active_set(end,3); li = active_set(end,4); idx = 0:(li-1); - solution(ti+idx) = max(0, active_set(end,1)/active_set(end,2)) * (g.^idx); - end - -end - %update the AR coefficient: g -function [c, active_set, g, s] = update_g(y, active_set, lam) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% active_set: npools*4 matrix, previous active sets. -% lam: scalar, curret value of sparsity penalty parameter lambda. - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization - -len_active_set = size(active_set, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(active_set(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% find the optimal g and get the warm started active_set -g = fminbnd(@rss_g, 0, 1); -yp = y - lam*(1-g); -for m=1:len_active_set - tmp_h = exp(log(g)*(0:maxl)'); % response kernel - tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - li = active_set(m, 4); - ti = active_set(m, 3); - idx = ti:(ti+li-1); - active_set(m,1) = (yp(idx))'*tmp_h(1:li); - active_set(m,2) = tmp_hh(li); -end -[c,s,active_set] = oasisAR2(y, g, lam, [], active_set); - -%% nested functions - function rss = rss_g(g) - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - yp = y - lam*(1-g); % include the penalty term - for ii=1:len_active_set - li = active_set(ii, 4); - ti = active_set(ii, 3); - idx = ti:(ti+li-1); - tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end -end \ No newline at end of file diff --git a/deconvolveCa/oasis/create_kernel.m b/deconvolveCa/oasis/create_kernel.m deleted file mode 100644 index 254de2e..0000000 --- a/deconvolveCa/oasis/create_kernel.m +++ /dev/null @@ -1,83 +0,0 @@ -function kernel = create_kernel(kernel_type, pars, nMax, lb, ub, bound_pars) -%% create convolution kernel -%% inputs: -% kernel_type: string, convolution kernel type. now support {'exp', -% 'exp2', 'vector'} -% pars: parameters for the selected kernel type -% nMax: length of the kernel -% lb: lower bound for each parameter -% ub: upper bound for each parameter -% bound_pars: logical variable, bound the parameters or not {1, 0} -%% outputs -% kernel: struct variable - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% kernel size -if ~exist('nMax', 'var') || isempty(nMax) - nMax = 50; -end -kernel.nMax = nMax; - -%% initialize kernel -if ~exist('kernel_type', 'var') || isempty(kernel_type) - kernel_type = 'exp2'; -end -if strcmpi(kernel_type, 'exp') - % single exponential function: ~ exp(-t/tau) - kernel.type = 'exp'; - % parameter - if ~exist('pars', 'var') || isempty(pars) - kernel.pars = [5, .1]; - else - kernel = kernel.pars; - end - % function handle - kernel.fhandle = @(pars, t) exp(-t/pars) * (1-exp(-1/pars)) ... - / (1-exp(-nMax/pars)); -elseif strcmpi(kernel_type, 'vector') - % single vector - kernel.type = 'vector'; - % parameter - if ~exist('pars', 'var') || isempty(pars) - kernel.pars = exp(-(1:nMax)/10); - else - kernel.pars = pars; - end - % function handle - kernel.fhandle = @(pars, t) pars/sum(pars); -else - % differencing of two exponential function: - % ~ exp(-t/tau_d)-exp(-t/tau_r) - kernel.type = 'exp2'; - - % parameters - if ~exist('pars', 'var') || isempty(pars) - kernel.pars = [10, 1]; - else - kernel.pars = pars; - end - % function handle - kernel.fhandle = @(pars, t) (exp(-t/pars(1)) - exp(-t/pars(2))) ... - /( (1-exp(-nMax/pars(1)))/(1-exp(-1/pars(1))) ... - - (1-exp(-nMax/pars(2)))/(1-exp(-1/pars(2)))); -end - -% lower and upper bounds for parameters -if ~exist('lb', 'var') || isempty(lb) - kernel.lb = 0.5*kernel.pars; -else - kernel.lb = lb; -end -if ~exist('ub', 'var') || isempty(ub) - kernel.ub = 2*kernel.pars; -else - kernel.ub = ub; -end - -% bound the parameters of not -if ~exist('bound_pars', 'var')||isempty(bound_pars) - kernel.bound_pars = false; -else - kernel.bound_pars = bound_pars; -end \ No newline at end of file diff --git a/deconvolveCa/oasis/deconvCa.m b/deconvolveCa/oasis/deconvCa.m deleted file mode 100644 index 4454ee9..0000000 --- a/deconvolveCa/oasis/deconvCa.m +++ /dev/null @@ -1,356 +0,0 @@ -function [c, s, kernel, iter] = deconvCa(y, kernel, smin, fit_gt, debug_on, sn, maxIter, theta, lambda) -%% deconvolve calcium traces to infer spike counts -%% inputs: -% y: 1*T vector, observed calcium traces -% kernel: struct variable with two fields {'fhandle', 'pars', nMax}. kernel -% deterines the convolution kernel -% fhandle: function handle, the function form of the response function -% pars: p*1 vector, parameters for fhandle -% nMax: scalar, maximum number of frames required by calcium indicators -% to return resting states -% smin: scalar, minimum number of nonzero spike count within each bin -% fit_gt: true or false. iteratively fit gt or not -% debug_on: play and save video of the whole procedure. -% sn: noise power -% maxIter: scalar, maximum iterations for running OASIS, default (3) -% theta: 1*T vecotr, weight vector at each time point -% lambda: scalar, tuning parameter - -%% outputs: -% c: 1*T vector, inferred calcium trace -% s: 1*T vector, inferred spike train -% kernel: convolution kernel -% iters: number of iterations for updating irf - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -% This work is based on one NIPS paper by Johannes Friedrich & Liam -% Paninski - -%% input arugments -y = reshape(y, 1, []); % convert data into row vector -if ~exist('sn', 'var') || isempty(sn) - sn = get_noise_fft(y); -end -T = length(y); % number of frames - -% get convolution kernel -if ~exist('kernel', 'var') || isempty(kernel) - kernel = create_kernel('exp2'); -end -fhandle = kernel.fhandle; -nMax = kernel.nMax; - -y = [y, zeros(1, nMax)]; % add few more elements for computation convenience - -% threshold of the spike -if ~exist('smin', 'var') || isempty(smin) - smin = 3*sn; % min spike count -else - smin = smin * sn; -end - -% fit response function or not -if ~exist('fit_gt', 'var') || isempty(fit_gt) - fit_gt = false; -end -thresh = 1e-3; - -% debug mode -if ~exist('debug_on', 'var') || isempty(debug_on) - debug_on = false; -end - -% maximum iterations for running OASIS -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 5; -end - -% tuning parameter for enforcing sparsity -if ~exist('lambda', 'var') || isempty(lambda) - lambda = 0; % tuning parameter -end - -% weight for each frame -if ~exist('theta', 'var')|| isempty(theta) || (length(theta)==1) % weight vector - theta = ones(1, T); -elseif length(theta)==T - theta = reshape(theta, 1, T); -else - disp('elements in theta should be equal to elements in y'); - return; -end - -% tuning parameter for enforcing sparsity -if ~exist('lambda', 'var') || isempty(lambda) - lambda = 0; % tuning parameter -end - -%% running OASIS -if debug_on - figure('position', [1, 1 1500, 250]); - plot(y); hold on; - a = plot(y, 'r'); - avi_file = VideoWriter('example.avi'); - avi_file.open(); - xlim([1, T]); -end - -f0 = inf; % objective function -y0 = y; % backup the raw trace -iter = 1; % iteratiosn -for iter = 1:maxIter - if debug_on - title(sprintf('Iter %d, norm(residual) = %.4f', iter, f0)); - end - % normalize gt to make its maximum value to be 1 - gt = fhandle(kernel.pars, 1:nMax); % 1*nMax, response function of calcium transients - ind0 = 1; %correct the response function of the first event - gt = [reshape(gt, 1, nMax), zeros(1, T)]; % add few more elements to gt for computation convenience - - gt_max = max(gt); - gt = gt/gt_max; - gt1 = [gt(ind0:end), zeros(1, ind0-1)]; % kernel for the first frame - - %% initialize values for the results - s = zeros(size(y)); % spike count within each bin - v = zeros(size(y)); % sum(theta_t*y_t) - lambda - w = zeros(size(y)); % sum(theta_t^2 * g(t-ti+1)^2)) - pool_ti = zeros(size(y)); % first frame of each pool - - % initialize the first pool - v(1) = theta(1)*y(1)*gt1(1) - lambda; - w(1) = (theta(1)*gt1(1))^2; - s(1) = max(0, v(1) / w(1)); - % if s(1)=nMax % no influences from the previous events - vi = theta(t)*y(t)*gt(1) - lambda; - elseif tpre>1 % estimate vi and subtract the effect of the previous event - vi = theta(t) * (y(t)-s(tpre)*gt(t-tpre+1)) * gt(1) - lambda; - else % special treatment with the first event - vi = theta(t) * (y(t)-s(tpre)*gt1(t-tpre+1)) * gt(1) - lambda; - end - wi = (theta(t) * gt(1))^2; - si = vi/wi; - - % check the violatoin of si - if si>smin && frame_valid % no violation, create a new pool to save the result and move to the next new pool - % peel off the previous event - if (t-tpre)1 - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) - s(tpre)*gt(1:nMax); - else - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) - s(tpre)*gt1(1:nMax); - end - end - pool_ti(ii) = t; % create a new pool - tpre = t; - v(t) = vi; - w(t) = wi; - s(t) = si; - ii = ii+1; % move to the next pool - t = t+1; - else % with violation - frame_valid = true; % allows the next frame to be valid - if (t-tpre)>=nMax - % ignore this frame directly and move to the next frame - t = t + 1; - continue; - elseif tpre>1 % merge it to the current pool - v(tpre) = v(tpre) + theta(t)*y(t)*gt(t-tpre+1); - w(tpre) = w(tpre) + (theta(t)*gt(t-tpre+1))^2; - else - v(tpre) = v(tpre) + theta(t)*y(t)*gt1(t-tpre+1); - w(tpre) = w(tpre) + (theta(t)*gt1(t-tpre+1)); - end - s(tpre) = v(tpre)/w(tpre); % update the current event - - % check the violation of the current pool - if s(tpre)>smin % the previous event is still avaiable - t = t+1; - continue; - elseif ii==2 %the previous pool is not available anymore, but it's the first pool - s(tpre) = max(0, s(tpre)); - t = t+1; - else % not available, then delete the current pool and force its first frame to be - % event-free. - t = tpre; % go back to the first frame of the current pull - - frame_valid = false; % force the frame t to be invalid - ii = ii-1; - tpre = pool_ti(ii-1); - - % add back the signal of the previous pool - if (t-tpre)>nMax - t = t+1; - frame_valid = true; - continue; - elseif tpre>1 - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) + s(tpre)*gt(1:nMax); - else - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) + s(tpre)*gt1(1:nMax); - end - end - end - end - %% collect the results - pool_ti(ii:end) = []; - temp = s(pool_ti); - s = zeros(1, T); - s(pool_ti) = temp; - temp = s; - temp(1) = 0; - c = conv(temp, gt(1:nMax)); - c = c(1:T) + s(1)*gt1(1:T); - f1 = norm(y(1:T)-c, 2); - s = s*sum(gt); - if debug_on - delete(a); - a = plot(c, 'r'); - drawnow(); - temp = getframe(); - temp.cdata = imresize(temp.cdata, [200, 1500]); - avi_file.writeVideo(temp); - end - - %% break the while loop - if ~fit_gt % don't iterate gt - break; - elseif (f0-f1)/f0 <= thresh % improvement is small, stop - break; - else % move to the next iteration - y = y0; - if strcmpi(kernel.type, 'exp2') - [kernel, ~] = update_kernel_exp2(y(1:T), s, kernel); - else - break; - end - f0 = f1; - iter = iter + 1; - % return; - end -end - -if debug_on - avi_file.close(); - close(gcf); -end -end - -%% estimate the noise power -function [sn,psdx,ff] = get_noise_fft(Y,options) -% Written by: -% Eftychios A. Pnevmatikakis, Simons Foundation, 2015 -% with minor adaption by Pengcheng Zhou, Carnegie Mellon University, 2015 -options.noise_range = [.25, .5]; -range_ff = options.noise_range; -options.noise_method = 'logmexp'; -method = options.noise_method; -options.block_size = [64, 64]; -block_size = options.block_size; -options.split_data = false; -split_data = options.split_data; -options.max_timesteps = 3000; - -dims = ndims(Y); -sizY = size(Y); -N = min(sizY(end),options.max_timesteps); -if N < sizY(end) - %Y = reshape(Y,prod(sizY(1:end-1)),[]); - Y(prod(sizY(1:end-1))*N+1:end) = []; - Y = reshape(Y,[sizY(1:end-1),N]); -end - -Fs = 1; -ff = 0:Fs/N:Fs/2; -indf=ff>range_ff(1); -indf(ff>range_ff(2))=0; -if dims > 1 - d = prod(sizY(1:dims-1)); - Y = reshape(Y,d,N); - Nb = prod(block_size); - SN = cell(ceil(d/Nb),1); - PSDX = cell(ceil(d/Nb),1); - if ~split_data - for ind = 1:ceil(d/Nb); - xdft = fft(Y((ind-1)*Nb+1:min(ind*Nb,d),:),[],2); - xdft = xdft(:,1: floor(N/2)+1); % FN: floor added. - psdx = (1/(Fs*N)) * abs(xdft).^2; - psdx(:,2:end-1) = 2*psdx(:,2:end-1); - %SN{ind} = mean_psd(psdx(:,indf),method); - switch method - case 'mean' - SN{ind}=sqrt(mean(psdx(:,indf)/2,2)); - case 'median' - SN{ind}=sqrt(median(psdx(:,indf)/2),2); - case 'logmexp' - SN{ind} = sqrt(exp(mean(log(psdx(:,indf)/2),2))); - end - PSDX{ind} = psdx; - end - else - nc = ceil(d/Nb); - Yc = mat2cell(Y,[Nb*ones(nc-1,1);d-(nc-1)*Nb],N); - parfor ind = 1:ceil(d/Nb); - xdft = fft(Yc{ind},[],2); - xdft = xdft(:,1:floor(N/2)+1); - psdx = (1/(Fs*N)) * abs(xdft).^2; - psdx(:,2:end-1) = 2*psdx(:,2:end-1); - Yc{ind} = []; - switch method - case 'mean' - SN{ind}=sqrt(mean(psdx(:,indf)/2,2)); - case 'median' - SN{ind}=sqrt(median(psdx(:,indf)/2),2); - case 'logmexp' - SN{ind} = sqrt(exp(mean(log(psdx(:,indf)/2),2))); - end - - end - end - sn = cell2mat(SN); -else - xdft = fft(Y); - xdft = xdft(:,1:floor(N/2)+1); - psdx = (1/(Fs*N)) * abs(xdft).^2; - psdx(:,2:end-1) = 2*psdx(:,2:end-1); - switch method - case 'mean' - sn = sqrt(mean(psdx(:,indf)/2,2)); - case 'median' - sn = sqrt(median(psdx(:,indf)/2),2); - case 'logmexp' - sn = sqrt(exp(mean(log(psdx(:,indf)/2),2))); - end -end -psdx = cell2mat(PSDX); -if dims > 2 - sn = reshape(sn,sizY(1:dims-1)); -end -end diff --git a/deconvolveCa/oasis/dsKernel.m b/deconvolveCa/oasis/dsKernel.m deleted file mode 100644 index 519fd76..0000000 --- a/deconvolveCa/oasis/dsKernel.m +++ /dev/null @@ -1,42 +0,0 @@ -function kernel_new = dsKernel(kernel, tsub) -%% downsample/upsample the convolution kernel -%% inputs: -% kernel: struct variable with fields {'kernel_type', 'pars', 'nMax', 'lb', 'ub', 'bound_pars'} -% kernel_type: string, convolution kernel type. now support {'exp', -% 'exp2', 'vector'} -% pars: parameters for the selected kernel type -% nMax: length of the kernel -% lb: lower bound for each parameter -% ub: upper bound for each parameter -% bound_pars: logical variable, bound the parameters or not {1, 0} -%% outputs -% kernel: struct variable - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -kernel_new = kernel; -if nargin<2 || isempty(tsub) - return; -end - -%% kernel size -kernel_new.nMax = ceil(kernel.nMax/tsub); - -%% kernel type -kernel_type = kernel.type; -if strcmpi(kernel_type, 'exp') - % single exponential function: ~ exp(-t/tau) - kernel_new.pars = kernel.pars/tsub; -elseif strcmpi(kernel_type, 'vector') - % single vector -len_kernel = length(kernel.pars); - kernel_new.pars = resample(kernel.pars, ceil(len_kernel/tsub), len_kernel); -else - % differencing of two exponential function: - % ~ exp(-t/tau_d)-exp(-t/tau_r) - kernel_new.pars = kernel.pars/tsub; -end - -%% lower and upper bounds for parameters -kernel_new.lb = kernel.lb / tsub; -kernel_new.ub = kernel.ub / tsub; \ No newline at end of file diff --git a/deconvolveCa/oasis/foopsi_oasisAR1.m b/deconvolveCa/oasis/foopsi_oasisAR1.m deleted file mode 100644 index d09c53e..0000000 --- a/deconvolveCa/oasis/foopsi_oasisAR1.m +++ /dev/null @@ -1,171 +0,0 @@ -function [c, s, b, g, active_set] = foopsi_oasisAR1(y, g, lam, smin, optimize_b,... - optimize_g, decimate, maxIter, gmax) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g c_{t-1} >= 0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets -% gmax: scalar, maximum value of g - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 1); -end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('smin', 'var') || isempty(smin) - smin = 0; -elseif smin<0 - smin = abs(smin) * GetSn(y); % use a threshold that is proportional to the noise level -end -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end - -%% optimize parameters -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks, active_set] = oasisAR1(y, g, lam, smin); - - %% iteratively update parameters g - if optimize_g % update g - [solution, active_set, g, spks] = update_g(y, active_set,lam, smin); - end -else - %% initialization - b = quantile(y, 0.15); - [solution, spks, active_set] = oasisAR1(y-b, g, lam, smin); - - %% iteratively update parameters g and b - for m=1:maxIter - b = mean(y-solution); - if optimize_g % update g - g0 = g; - if g>gmax % spike counts are too small. stop - g = estimate_time_constant(y, 1); - [solution, spks, active_set] = oasisAR1(y-b, g, lam, smin); - break; - end - if isempty(active_set) - break; - end - [solution, active_set, g, spks] = update_g(y-b, active_set,lam, smin); - if abs(g-g0)/g0 < 1e-3 % g is converged - optimize_g = false; - end - else - break; - end - end -end -c = solution; -s = spks; -end -%update the AR coefficient: g -function [c, active_set, g, s] = update_g(y, active_set, lam, smin) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% active_set: npools*4 matrix, previous active sets. -% lam: scalar, curret value of sparsity penalty parameter lambda. - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization - -len_active_set = size(active_set, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(active_set(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% find the optimal g and get the warm started active_set -g = fminbnd(@rss_g, 0, 1); -yp = y - lam*(1-g); -for m=1:len_active_set - tmp_h = exp(log(g)*(0:maxl)'); % response kernel - tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - li = active_set(m, 4); - ti = active_set(m, 3); - idx = ti:(ti+li-1); - active_set(m,1) = (yp(idx))'*tmp_h(1:li); - active_set(m,2) = tmp_hh(li); -end -[c,s,active_set] = oasisAR1(y, g, lam, smin, active_set); - -%% nested functions - function rss = rss_g(g) - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - yp = y - lam*(1-g); % include the penalty term - for ii=1:len_active_set - li = active_set(ii, 4); - ti = active_set(ii, 3); - idx = ti:(ti+li-1); - tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end -end \ No newline at end of file diff --git a/deconvolveCa/oasis/foopsi_oasisAR2.m b/deconvolveCa/oasis/foopsi_oasisAR2.m deleted file mode 100644 index be475d4..0000000 --- a/deconvolveCa/oasis/foopsi_oasisAR2.m +++ /dev/null @@ -1,191 +0,0 @@ -function [c, s, b, g, active_set] = foopsi_oasisAR2(y, g, lam, smin, optimize_b,... - optimize_g, decimate, maxIter) -%% Infer the most likely discretized spike train underlying an AR(2) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g_1 c_{t-1}- g_2 c_{t-2} >= 0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: 1*2 vector, Parameter of the AR(2) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter -% smin: scalar, minimum spike size -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 2); -end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end - -if ~exist('smin', 'var') || isempty(smin); - smin = 0; -end -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end - -%% optimize parameters -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks, active_set] = oasisAR2(y, g, lam, smin); - - %% iteratively update parameters g - if optimize_g; - g_old = g; - g = update_g(y-b, g, spks); - [solution, spks,active_set] = oasisAR2(y, g, 0, smin); - end -else - disp('to be done'); -% %% initialization -% b = quantile(y, 0.15); -% [solution, spks, active_set] = oasisAR2(y-b, g, lam, smin); -% - %% iteratively update parameters g and b -% for m=1:maxIter -% b = mean(y-solution); -% if and(optimize_g, ~g_converged); -% g0 = g; -% g = update_g(y-b, g, spks); -% smin = choose_smin(g, sn, 0.9999); -% [solution, spks,active_set] = oasisAR2(y, g, 0, smin); -% -% if norm(g-g0,2)/norm(g0) < 1e-3 % g is converged -% g_converged = true; -% end -% else -% break; -% end -% end -end -c = solution; -s = spks; -end - - -%update the AR coefficient: g -function g = update_g(y, g, spks) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: 2x1 vector, AR2 parameters -% active_set: npools*4 matrix, previous active sets. -% smin: scalr, minimize size of nonzero spikes - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% initialization -s_th = quantile(spks(spks>1e-3), 0.25); -tsp = find(spks>=s_th); -tsp = reshape(tsp, 1, []); -time_p = find(conv2(double(spks<=s_th), ones(30,1), 'same')>0); -time_p = reshape(time_p,[],1); -y = reshape(y,[],1); % fluorescence data -yp = y(time_p); -T = length(y); -tau_dr = ar2exp(g); -tau_d = tau_dr(1); -tau_r = tau_dr(2); -warning('off', 'MATLAB:singularMatrix'); - -%% find the optimal g and get the warm started active_set -tau_d0 = tau_d; -tau_r0 = tau_r; -bnd_d = tau_d0 * [1/4, 4]; -bnd_r = tau_r0 * [1/4, 4]; -for m=1:10 - tau_r = fminbnd(@rss_taur, bnd_r(1), bnd_r(2)); - tau_d = fminbnd(@rss_taud, bnd_d(1), bnd_d(2)); - if and(abs(tau_d-tau_d0)/tau_d0 < 1e-4, abs(tau_r-tau_r0)/tau_r0 < 1e-4) - break; - else - tau_d0 = tau_d; - tau_r0 = tau_r; - end -end - -%% compute the optimal solution -g = exp2ar([tau_d, tau_r]); - -%% nested functions - - function rss = rss_taur(tau_r) - ht = (exp(-(1:T)/tau_d) - exp(-(1:T)/tau_r))/(tau_d-tau_r); - ht(T) = 0; - ind = bsxfun(@minus, time_p, tsp); - ind(ind<=0) = T; - V = ht(ind); - - % find the best value of st - s = (V'*V)\(V'*yp); - res = yp - V*s; - rss = res' * res; - end - - function rss = rss_taud(tau_d) - ht = (exp(-(1:T)/tau_d) - exp(-(1:T)/tau_r))/(tau_d-tau_r); - ht(T) = 0; - ind = bsxfun(@minus, time_p, tsp); - ind(ind<=0) = T; - V = ht(ind); - - % find the best value of st - s = (V'*V)\(V'*yp); - res = yp - V*s; - rss = res' * res; - end -end \ No newline at end of file diff --git a/deconvolveCa/oasis/oasisAR1.m b/deconvolveCa/oasis/oasisAR1.m deleted file mode 100644 index f7bb114..0000000 --- a/deconvolveCa/oasis/oasisAR1.m +++ /dev/null @@ -1,109 +0,0 @@ -function [c, s, active_set] = oasisAR1(y, g, lam, smin, active_set) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g c_{t-1} >=s_min or =0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% OR %% -% len_active_set*4 matrix, active set - -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter lambda. -% smin: scalar, optional, default 0 -%miniumal non-zero activity within each bin (minimal 'spike size'). -% active_set: npool x 4 matrix, warm stared active sets - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization -y = reshape(y, [], 1); -if isempty(y) - T = sum(active_set(:,4)); -else -T = length(y); -end -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y); -elseif length(g)>1 - c = zeros(T,1); - s = zeros(T,1); - active_set = []; - return; -end -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('smin', 'var') || isempty(smin); smin = 0; end -if ~exist('active_set', 'var') || isempty(active_set) - len_active_set = T; - active_set = [y-lam*(1-g),ones(T,1),(1:T)',ones(T,1),(1:T)'-1, (1:T)'+1]; % each row is one pool: (vi, wi, t, l) - active_set(end, :) = [y(end)-lam,1,T,1,T-1,nan] ; - active_set(1,5) = nan; -else - len_active_set = size(active_set,1); - active_set(:,5) = [nan; (1:len_active_set-1)']; - active_set(:,6) = [(2:len_active_set)';nan]; -end -idx = true(len_active_set,1); - -%% run OASIS -ii = 1; -ii_next = active_set(ii,6); -while ~isnan(ii_next) - % find the active set - while (~isnan(ii_next)) && (active_set(ii_next,1)/active_set(ii_next,2)... - >=active_set(ii,1)/active_set(ii,2)*g^(active_set(ii,4))+smin) - active_set(ii_next,5) = ii; - ii = ii_next; - ii_next = active_set(ii,6); - end - - if isnan(ii_next); break; end - - %% merge pools - active_set(ii,1) = active_set(ii,1) + active_set(ii_next,1)* (g^(active_set(ii,4))); - active_set(ii,2) = active_set(ii,2) + active_set(ii_next,2)*(g^(2*active_set(ii,4))); - active_set(ii,4) = active_set(ii,4) + active_set(ii_next,4); - active_set(ii,6) = active_set(ii_next,6); - idx(ii_next) = false; - ii_next = active_set(ii,6); - ii_prev = active_set(ii, 5); - - %% backtrack until violations fixed - while (~isnan(ii_prev)) && (active_set(ii,1)/active_set(ii,2)<... - active_set(ii_prev,1)/active_set(ii_prev,2)*g^(active_set(ii_prev,4))+smin) - ii_next = ii; - ii = ii_prev; - active_set(ii,1) = active_set(ii,1) + active_set(ii_next,1)* (g^(active_set(ii,4))); - active_set(ii,2) = active_set(ii,2) + active_set(ii_next,2)*(g^(2*active_set(ii,4))); - active_set(ii,4) = active_set(ii,4) + active_set(ii_next,4); - active_set(ii,6) = active_set(ii_next,6); - idx(ii_next) = false; - - ii_prev = active_set(ii, 5); - ii_next = active_set(ii,6); - end -end -active_set(~idx, :) = []; -len_active_set = size(active_set,1); - -%% construct solution for all t -c = zeros(T, 1); -s = c; -for ii=1:len_active_set - t0 = active_set(ii,3); - tau = active_set(ii, 4); - c(t0:(t0+tau-1)) = max(0,active_set(ii,1)/active_set(ii,2)) * (g.^(0:(tau-1))); -end - -s(active_set(2:end,3)) = c(active_set(2:end,3)) - g*c(active_set(2:end,3)-1); diff --git a/deconvolveCa/oasis/oasisAR2.m b/deconvolveCa/oasis/oasisAR2.m deleted file mode 100644 index e11e69d..0000000 --- a/deconvolveCa/oasis/oasisAR2.m +++ /dev/null @@ -1,156 +0,0 @@ -function [c, s, active_set] = oasisAR2(y, g, lam, smin, T_over_ISI, jitter, active_set) -%% Infer the most likely discretized spike train underlying an AR(2) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g1*c_{t-1}-g2*c_{t-2} >=s_min or =0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g1: scalar, first parameter of the AR(2) process that models the fluorescence ... -%impulse response. -% g2: scalar, second parameter of the AR(2) process that models the fluorescence ... -%impulse response. -% lam: scalar, sparsity penalty parameter lambda. -% smin: scalar, optional, default 0 -%miniumal non-zero activity within each bin (minimal 'spike size'). -% T_over_ISI: scalar, ratio of recording duration T and maximumal -% inter-spike-interval. default: 1 -% jitter: bool, perform correction step by jittering spike times to -% minimize RSS. it helps to avoid delayed spike detection. default: -% false; - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% active_set: npool * 4 matrix, active set - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization -y = reshape(y, [], 1); -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 2); -end -g1 = g(1); -g2 = g(2); - -if ~exist('lam', 'var') || isempty(lam); lam = 0; end -if ~exist('smin', 'var') || isempty(smin); smin = 0; end -if ~exist('T_over_ISI', 'var') || isempty(T_over_ISI) - T_over_ISI = 1; -end -if ~exist('jitter', 'var') || isempty(jitter) - jitter = false; -end - -%% initialization -T = length(y); -yp = y - lam * (1-g1-g2); -yp(end-1) = y(end-1) - lam*(1-g1); -yp(end) = y(end) - lam; - -if ~exist('active_set', 'var') || isempty(active_set) - % active set - len_active_set = length(y); - active_set = [yp, yp, (1:T)', ones(T,1), (1:T)'-1, (1:T)'+1]; - active_set(1,5) = nan; - active_set(end,6) = nan; -else - len_active_set = size(active_set,1); - active_set(:,5) = [nan;(1:len_active_set-1)']; - active_set(:,6) = [(2:len_active_set)';nan]; -end -idx = true(len_active_set,1); - -% precompute -len_g = T / T_over_ISI; -temp = roots([1, -g1, -g2]); -d = max(temp); r = min(temp); -g11 = (exp(log(d)*(1:len_g)') - exp(log(r)*(1:len_g)')) / (d-r); -g12 = [0; g2*g11(1:(end-1))]; -g11g11 = cumsum(g11.*g11); -g11g12 = cumsum(g11.*g12); - -%% run OASIS -ii = 2; -ii_next = active_set(ii,6); -ii_prev = active_set(ii,5); -while ~isnan(ii_next) - % find the active set - while (~isnan(ii_next)) && (g11(active_set(ii,4)+1)*active_set(ii,1) + ... - g12(active_set(ii,4)+1)*active_set(ii_prev,2) + smin <= active_set(ii_next,1)) - active_set(ii_next,5) = ii; - ii = ii_next; % move to the next pool - ii_next = active_set(ii,6); - ii_prev = active_set(ii,5); - end - if isnan(ii_next); break; end - - %% merge pools - active_set(ii, 4) = active_set(ii, 4) + active_set(ii_next, 4); - ti = active_set(ii,3); - li = active_set(ii,4); - active_set(ii,1) = (g11(1:li)'*yp(ti+(1:li)-1) - g11g12(li)*active_set(ii_prev,2))/g11g11(li); - active_set(ii,2) = g11(li)*active_set(ii,1) + g12(li)*active_set(ii_prev,2); - idx(ii_next) = false; - active_set(ii,6) = active_set(ii_next, 6); - ii_next = active_set(ii, 6); - if ~isnan(ii_next) - active_set(ii_next,5) = ii; - end - - ii_prev_1 = active_set(ii,5); - ii_prev_2 = active_set(ii_prev_1,5); - %% backtrack until violations fixed - while (~isnan(ii_prev_2)) && (g11(active_set(ii_prev_1,4)+1)*active_set(ii_prev_1,1) + g12(active_set(ii_prev_1,4)+1)... - *active_set(ii_prev_2,2) + smin > active_set(ii,1)) - ii_next = ii; - ii = ii_prev_1; - ii_prev = ii_prev_2; - - active_set(ii, 4) = active_set(ii, 4) + active_set(ii_next, 4); - ti = active_set(ii,3); - li = active_set(ii,4); - active_set(ii,1) = (g11(1:li)'*yp(ti+(1:li)-1) - g11g12(li)*active_set(ii_prev,2))/g11g11(li); - active_set(ii,2) = g11(li)*active_set(ii,1) + g12(li)*active_set(ii_prev,2); - idx(ii_next) = false; - active_set(ii,6) = active_set(ii_next, 6); - ii_next = active_set(ii, 6); - if ~isnan(ii_next) - active_set(ii_next,5) = ii; - end - ii_prev_1 = active_set(ii,5); - ii_prev_2 = active_set(ii_prev_1,5); - end - -end - -%% jitter -% a_s = active_set; -if jitter - disp('to be done\n'); -end - -active_set(~idx, :) = []; -len_active_set = size(active_set,1); - -%% construct solution for all t -c = zeros(T,1); -for ii=1:len_active_set - vi = active_set(ii,1); - ti = active_set(ii,3); - li = active_set(ii,4); - c(ti) = vi; - - for m=1:(li-1) - c(ti+m) = g1*c(ti+m-1) + g2*c(ti+m-2); - end -end -c(c<0) = 0; - -s = [0;0;0; c(4:end)-g1*c(3:(end-1))-g2*c(2:(end-2))]; -s(s= 0 - -%% inputs: -% y: T*1 vector, vth dimensional array containing the fluorescence intensities - %withone entry per time-bin. -% g: vector, shape (p,) -% if p in (1,2): AR coefficients for AR(p) process -% else: kernel that models the fluorescence implulse response -% lam: scalar, sparsity penalty parameter lambda. -% shift: integer scalar, number of frames by which to shift window from on run of -% NNLS to the next, default-100 -% win: integer acalar, window size -% tol: scalar, tolerance parameters -% maxIter: scalar, maximum number of iterations before termination -% mask: T * 1 boolean vector, restrict potential spike times -% smin: scalar, minimum spike size -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% input arguments -T = length(y); -y = reshape(y, [], 1); - -if ~exist('lam', 'var') || isempty(lam) - lam = 0; -end -if ~exist('shift', 'var') || isempty(shift) - shift = 100; -end -if ~exist('win', 'var') || isempty(win) - win = 200; -end - -if ~exist('tol', 'var') || isempty(tol) - tol = 1e-9; -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = []; -end -if ~exist('mask', 'var') || isempty(mask) - mask = true(T,1); -end -if ~exist('smin', 'var') || isempty(smin) - smin = 0; -end -%% get the response kernel -w = win; -K = zeros(w); -[u, t] = meshgrid(1:w, 1:w); -ind = 1+t-u; -if length(g)==1 - h = exp(log(g)*(0:(w-1))); -elseif length(g)==2 - temp = roots([1, -g(1), -g(2)]); - d = max(temp); - r = min(temp); - h = (exp(log(d)*(1:w)) - exp(log(r)*(1:w))) / (d-r); % convolution kernel -else - h = g; -end -K(ind>0) = h(ind(ind>0)); % convolution matrix -KK = K'*K; - -%% initialization -a = sum(inv(K)); -yp = y - lam * a(1); -yp((end-w+1):end) = yp((end-w+1):end) - lam * a'; -s = zeros(T, 1); -c = zeros(T, 1); - -%% run online deconvolution -t = 1; -yp0 = yp; -while t <= T-w+1 - ind = t:(t+w-1); - s(ind) = nnls(KK, K'*yp(ind), s(ind), tol, maxIter, mask(ind)); - yp(ind) = yp(ind) - K(:, 1:shift)*s(t:(t+shift-1)); - c(ind) = c(ind) + K(:, 1:shift)*s(t:(t+shift-1)); - t = t + shift; -end -s(t:T) = nnls(KK((t+w-T):w, (t+w-T):w), K(1:(T-t+1), 1:(T-t+1))'*yp(t:T), ... - s(t:T), tol, maxIter, mask(t:T)); -c(t:T) = c(t:T) + K((t+w-T):w, (t+w-T):w) * s(t:T); - -%% running thresholded version -if smin>0 - yp = yp0; - c = zeros(size(c)); - mask = (s>smin/100); - t = 1; - while t <= T-w+1 - ind = t:(t+w-1); - s(ind) = nnls(KK, K'*yp(ind), s(ind), tol, maxIter, mask(ind), smin); - yp(ind) = yp(ind) - K(:, 1:shift)*s(t:(t+shift-1)); - c(ind) = c(ind) + K(:, 1:shift)*s(t:(t+shift-1)); - t = t + shift; - end - s(t:T) = nnls(KK((t+w-T):w, (t+w-T):w), K(1:(T-t+1), 1:(T-t+1))'*yp(t:T), ... - s(t:T), tol, maxIter, mask(t:T), smin); - c(t:T) = c(t:T) + K((t+w-T):w, (t+w-T):w) * s(t:T); -end - - -function s = nnls(KK, Ky, s, tol, maxIter, mask, smin) -%% fast algorithm for solving nonnegativity constrained least squared -% problem minize norm(y-K*s, 2), s.t. s>=0. - -%% inputs: -% KK: p x p matrix, K'*K -% Ky: n x 1 vector, K'*y -% s: p x 1 vector, warm started s -% tol: scalar, smallest nonzero values -% maxIter: scalar, maximum nonzero values -% mask: p x 1 vector, mask to restrict potential spike times considered -% smin: scala, minimize size of the spike - -%% outputs: -% s: p x 1 vector, solution - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging -% Bro R & Jong S, Journal of Chemometrics 1997, A FAST NON-NEGATIVITY-CONSTRAINED LEAST SQUARES ALGORITHM - - -%% input arguments -if ~exist('mask', 'var')||isempty(mask) - mask = true(size(KK,1), 1); -elseif any(mask) - KK = KK(mask, mask); - Ky = Ky(mask); -else - s = double(mask); - return; -end - -p = size(KK,2); % dimension of s -if ~exist('smin', 'var') || isempty(smin) - smin = 0; -end -vth = ones(p,1)*smin; -if ~exist('s', 'var') || isempty(s) - s = zeros(p, 1); - l = Ky; - Pset = false(p,1); -else - s = s(mask); - s = s - smin; - Pset = (s>0); - s(~Pset) = 0; - l = Ky - KK*s - KK * Pset*smin; -end -if ~exist('tol', 'var') || isempty(tol) - tol = 1e-9; -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = p; -end - - -% outer loop: loop for passive set -[~, ind] = max(l); -for miter =1:maxIter - % remove element from the active set - Pset(ind) = true; - - % solve unconstrained least squares over the passive set - try - mu = KK(Pset, Pset) \ (Ky(Pset)-KK(Pset, Pset)*vth(Pset)); - catch % sigular issue - mu = (KK(Pset, Pset) + tol*eye(sum(Pset))) \ (Ky(Pset)... - -KK(Pset, Pset)*vth(Pset)); - end - - % inner loop: correct nonnegativity violations - while any(mu<=0) - temp = s(Pset) ./ (s(Pset)-mu); - a = min(temp(mu<0)); - s(Pset) = s(Pset) + a*(mu-s(Pset)); - Pset(s<=tol) = false; - - % solve unconstrained least squares over the passive set - try - mu = KK(Pset, Pset) \ (Ky(Pset)-KK(Pset, Pset)*vth(Pset)); - catch % sigular issue - mu = (KK(Pset, Pset) + tol*eye(sum(Pset))) \ (Ky(Pset)... - -KK(Pset, Pset)*vth(Pset)); - end - end - - s(Pset) = mu; - l = Ky - KK*s - KK*Pset*smin; - % at least one iteration - [lmax, ind] = max(l); - if lmax < tol % no more passive set - break; - end -end -s(Pset) = mu + smin; -temp = double(mask); -temp(mask) = s; -s = temp; diff --git a/deconvolveCa/oasis/test_oasis.m b/deconvolveCa/oasis/test_oasis.m deleted file mode 100644 index 6f888a6..0000000 --- a/deconvolveCa/oasis/test_oasis.m +++ /dev/null @@ -1,34 +0,0 @@ -%% function -clear; clc; close all; -T = 1000; -s = double(rand(1, T)>0.98); -sig = 0.04; - -% example -tau_d = 5; -tau_r = 1; -nMax = 100; -pars = [tau_d, tau_r]; -kernel = create_kernel('exp2', pars, nMax); - -t = 1:kernel.nMax; -gt = kernel.fhandle(kernel.pars, t); -c1 = conv(s, gt); -c1 = c1(1:T); -y1 = c1 + randn(1, T) * sig; - -%% use the true convolution kernel -kernel0 = kernel; -kernel0.pars = [10, 0.1]; -kernel0.bound_pars = false; -figure('position', [1,1,1500, 200]); -plot(y1); -hold on; -plot(c1, 'r', 'linewidth', 2); -plot(-s*0.1, 'r', 'linewidth', 2); -tic; -[chat, shat, kernel_fit, iters] = deconvCa(y1, kernel0, 2, true, false); -toc; -plot(chat,'-.g','linewidth', 2); -plot(-shat*0.1, '-.g', 'linewidth', 2); %, '-.'); -legend('data', 'ground truth: c','ground truth: s', 'OASIS:c', 'OASIS: s'); % 'gound truth: s', 'OASIS: c', 'OASIS: s'); \ No newline at end of file diff --git a/deconvolveCa/oasis/thresholded_nnls.m b/deconvolveCa/oasis/thresholded_nnls.m deleted file mode 100644 index 0a612fe..0000000 --- a/deconvolveCa/oasis/thresholded_nnls.m +++ /dev/null @@ -1,220 +0,0 @@ -function [c, s] = thresholded_nnls(y, g, sn, smin, shift, win, tol, maxIter, mask, thresh_factor) -%% Infer the most likely discretized spike train underlying an AR(2) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|Ks-y|^2 + lam * |s|_1 subject to s_t = c_t-g c_{t-1} >= 0 - -%% inputs: -% y: T*1 vector, vth dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: vector, shape (p,) -% if p in (1,2): AR coefficients for AR(p) process -% else: kernel that models the fluorescence implulse response -% sn: scalar, standard deviation of the noise -% smin: scalar, minimum spike size -% shift: integer scalar, number of frames by which to shift window from on run of -% NNLS to the next, default-100 -% win: integer acalar, window size -% tol: scalar, tolerance parameters -% maxIter: scalar, maximum number of iterations before termination -% mask: T * 1 boolean vector, restrict potential spike times -% smin: scalar, minimum spike size -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% input arguments -T = length(y); -y = reshape(y, [], 1); - -if ~exist('sn', 'var') || isempty(sn) - sn = GetSn(y); -end -if ~exist('shift', 'var') || isempty(shift) - shift = 100; -end -if ~exist('win', 'var') || isempty(win) - win = 200; -end - -if ~exist('tol', 'var') || isempty(tol) - tol = 1e-9; -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = []; -end -if ~exist('mask', 'var') || isempty(mask) - mask = true(T,1); -end -if ~exist('smin', 'var') || isempty(smin) - smin = 0; -end - -thresh = thresh_factor* sn * sn * T; - -%% get the response kernel -w = win; -K = zeros(w); -[u, t] = meshgrid(1:w, 1:w); -ind = 1+t-u; -if length(g)==1 - h = exp(log(g)*(0:(w-1))); -elseif length(g)==2 - temp = roots([1, -g(1), -g(2)]); - d = max(temp); - r = min(temp); - h = (exp(log(d)*(1:w)) - exp(log(r)*(1:w))) / (d-r); % convolution kernel -else - h = g; -end -K(ind>0) = h(ind(ind>0)); % convolution matrix -KK = K'*K; - -%% initialization -a = sum(inv(K)); -yp = y - lam * a(1); -yp((end-w+1):end) = yp((end-w+1):end) - lam * a'; -s = zeros(T, 1); -c = zeros(T, 1); - -%% run online deconvolution -t = 1; -yp0 = yp; -while t <= T-w+1 - ind = t:(t+w-1); - s(ind) = nnls(KK, K'*yp(ind), s(ind), tol, maxIter, mask(ind)); - yp(ind) = yp(ind) - K(:, 1:shift)*s(t:(t+shift-1)); - c(ind) = c(ind) + K(:, 1:shift)*s(t:(t+shift-1)); - t = t + shift; -end -s(t:T) = nnls(KK((t+w-T):w, (t+w-T):w), K(1:(T-t+1), 1:(T-t+1))'*yp(t:T), ... - s(t:T), tol, maxIter, mask(t:T)); -c(t:T) = c(t:T) + K((t+w-T):w, (t+w-T):w) * s(t:T); - -%% running thresholded version for fast initialization -if smin>0 - yp = yp0; - c = zeros(size(c)); - mask = (s>1e-4); - t = 1; - while true - % [tmp_min, ind] = min(s(mask)); - ind = t:(t+w-1); - s(ind) = nnls(KK, K'*yp(ind), s(ind), tol, maxIter, mask(ind), smin); - yp(ind) = yp(ind) - K(:, 1:shift)*s(t:(t+shift-1)); - c(ind) = c(ind) + K(:, 1:shift)*s(t:(t+shift-1)); - t = t + shift; - end - s(t:T) = nnls(KK((t+w-T):w, (t+w-T):w), K(1:(T-t+1), 1:(T-t+1))'*yp(t:T), ... - s(t:T), tol, maxIter, mask(t:T), smin); - c(t:T) = c(t:T) + K((t+w-T):w, (t+w-T):w) * s(t:T); -end - -%% - -function s = nnls(KK, Ky, s, tol, maxIter, mask, smin) -%% fast algorithm for solving nonnegativity constrained least squared -% problem minize norm(y-K*s, 2), s.t. s>=0. - -%% inputs: -% KK: p x p matrix, K'*K -% Ky: n x 1 vector, K'*y -% s: p x 1 vector, warm started s -% tol: scalar, smallest nonzero values -% maxIter: scalar, maximum nonzero values -% mask: p x 1 vector, mask to restrict potential spike times considered -% smin: scala, minimize size of the spike - -%% outputs: -% s: p x 1 vector, solution - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging -% Bro R & Jong S, Journal of Chemometrics 1997, A FAST NON-NEGATIVITY-CONSTRAINED LEAST SQUARES ALGORITHM - - -%% input arguments -if ~exist('mask', 'var')||isempty(mask) - mask = true(size(KK,1), 1); -elseif any(mask) - KK = KK(mask, mask); - Ky = Ky(mask); -else - s = double(mask); - return; -end - -p = size(KK,2); % dimension of s -if ~exist('smin', 'var') || isempty(smin) - smin = 0; -end -vth = ones(p,1)*smin; -if ~exist('s', 'var') || isempty(s) - s = zeros(p, 1); - l = Ky; - Pset = false(p,1); -else - s = s(mask); - s = s - smin; - Pset = (s>0); - s(~Pset) = 0; - l = Ky - KK*s - KK * Pset*smin; -end -if ~exist('tol', 'var') || isempty(tol) - tol = 1e-9; -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = p; -end - - -% outer loop: loop for passive set -[~, ind] = max(l); -for miter =1:maxIter - % remove element from the active set - Pset(ind) = true; - - % solve unconstrained least squares over the passive set - try - mu = KK(Pset, Pset) \ (Ky(Pset)-KK(Pset, Pset)*vth(Pset)); - catch % sigular issue - mu = (KK(Pset, Pset) + tol*eye(sum(Pset))) \ (Ky(Pset)... - -KK(Pset, Pset)*vth(Pset)); - end - - % inner loop: correct nonnegativity violations - while any(mu<=0) - temp = s(Pset) ./ (s(Pset)-mu); - a = min(temp(mu<0)); - s(Pset) = s(Pset) + a*(mu-s(Pset)); - Pset(s<=tol) = false; - - % solve unconstrained least squares over the passive set - try - mu = KK(Pset, Pset) \ (Ky(Pset)-KK(Pset, Pset)*vth(Pset)); - catch % sigular issue - mu = (KK(Pset, Pset) + tol*eye(sum(Pset))) \ (Ky(Pset)... - -KK(Pset, Pset)*vth(Pset)); - end - end - - s(Pset) = mu; - l = Ky - KK*s - KK*Pset*smin; - % at least one iteration - [lmax, ind] = max(l); - if lmax < tol % no more passive set - break; - end -end -s(Pset) = mu + smin; -temp = double(mask); -temp(mask) = s; -s = temp; diff --git a/deconvolveCa/oasis/thresholded_oasisAR1.m b/deconvolveCa/oasis/thresholded_oasisAR1.m deleted file mode 100644 index 99115c8..0000000 --- a/deconvolveCa/oasis/thresholded_oasisAR1.m +++ /dev/null @@ -1,266 +0,0 @@ -function [c, s, b, g, smin, active_set] = thresholded_oasisAR1(y, g, sn, optimize_b,... - optimize_g, decimate, maxIter, thresh_factor, p_noise) -%% Infer the most likely discretized spike train underlying an AR(1) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 subject to s_t = c_t-g c_{t-1} >=s_min or =0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% sn: scalar, standard deviation of the noise distribution -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets -% thresh_factor: scalar, set the maximum thresh as thresh_factor*sn^2*T -% smin_p: scalar, the probability of rejecting false spikes resulted from -% noise - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% smin: scalar, minimum nonzero spike count -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 1); - g = g(1); -end - -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end - -if ~exist('sn', 'var') || isempty(sn) - if optimize_b - [b, sn] = estimate_baseline_noise(y); - else - [~, sn] = estimate_baseline_noise(y); - end -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end -if ~exist('thresh_factor', 'var') || isempty(thresh_factor) - thresh_factor = 1.0; -end -if ~exist('p_noise', 'var') || isempty(p_noise) - p_noise = 0.9999; -end - -% thresh = thresh_factor* sn * sn * T; -smin = choose_smin(g, sn, p_noise); -thresh = thresh_factor* sn * sn * T; - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end -g_converged = false; - -%% optimize parameters -tol = 1e-4; -if ~optimize_b %% don't optimize the baseline b - b = 0; - %% initialization - [solution, spks, active_set] = oasisAR1(y, g, [], smin); - - res = y - solution; - RSS0 = res' * res; - %% optimize the baseline b and dependends on the optimized g too - for miter=1:maxIter - if isempty(active_set) - break; - end - % update b and g - if and(optimize_g, ~g_converged); - g0 = g; - [solution, active_set, g, spks] = update_g(y, active_set, smin); - if abs(g-g0)/g0 < 1e-4; - g_converged = true; - end - end - - res = y - solution; - RSS = res' * res; - if abs(RSS-RSS0)1 - ind = floor((ind_start+ind_end)/2); - tmp_smin = sv(ind); - [tmp_solution, tmp_spks, tmp_active_set] = oasisAR1([], g, [], ... - tmp_smin, active_set); - sqRSS = norm(y-tmp_solution,2); - if sqRSSthresh % decrease smin - ind_end = ind; - else - break; - end - end - end - - -end - -%update the AR coefficient: g -function [c, active_set, g, s] = update_g(y, active_set, smin) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% active_set: npools*4 matrix, previous active sets. -% smin: scalr, minimize size of nonzero spikes - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization - -len_active_set = size(active_set, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(active_set(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% find the optimal g and get the warm started active_set -g = fminbnd(@rss_g, 0, 1); -yp = y; -for m=1:len_active_set - tmp_h = exp(log(g)*(0:maxl)'); % response kernel - tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - li = active_set(m, 4); - ti = active_set(m, 3); - idx = ti:(ti+li-1); - active_set(m,1) = (yp(idx))'*tmp_h(1:li); - active_set(m,2) = tmp_hh(li); -end -[c,s,active_set] = oasisAR1(y, g, 0, smin, active_set); - -%% nested functions - function rss = rss_g(g) - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - yp = y; % include the penalty term - for ii=1:len_active_set - li = active_set(ii, 4); - ti = active_set(ii, 3); - idx = ti:(ti+li-1); - tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end -end \ No newline at end of file diff --git a/deconvolveCa/oasis/thresholded_oasisAR2.m b/deconvolveCa/oasis/thresholded_oasisAR2.m deleted file mode 100644 index f93512b..0000000 --- a/deconvolveCa/oasis/thresholded_oasisAR2.m +++ /dev/null @@ -1,322 +0,0 @@ -function [c, s, b, g, smin, active_set] = thresholded_oasisAR2(y, g, sn, smin, optimize_b,... - optimize_g, decimate, maxIter, thresh_factor) -%% Infer the most likely discretized spike train underlying an AR(2) fluorescence trace -% Solves the sparse non-negative deconvolution problem -% min 1/2|c-y|^2 + lam |s|_1 subject to s_t = c_t-g_1*c_{t-1} - g_2*c_{t-2}>=s_min or =0 - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% sn: scalar, standard deviation of the noise distribution -% optimize_b: bool, optimize baseline if True -% optimize_g: integer, number of large, isolated events to consider for -% optimizing g -% decimate: int, decimation factor for estimating hyper-parameters faster -% on decimated data -% maxIter: int, maximum number of iterations -% active_set: npool x 4 matrix, warm stared active sets -% thresh_factor: scalar, set the maximum thresh as thresh_factor*sn^2*T - -%% outputs -% c: T*1 vector, the inferred denoised fluorescence signal at each time-bin. -% s: T*1 vector, discetized deconvolved neural activity (spikes) -% b: scalar, fluorescence baseline -% g: scalar, parameter of the AR(1) process -% smin: scalar, minimum nonzero spike count -% active_set: npool x 4 matrix, active sets - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - - -%% input arguments -y = reshape(y, [], 1); -T = length(y); - -if ~exist('g', 'var') || isempty(g) - g = estimate_time_constant(y, 2); -end - -if ~exist('optimize_b', 'var') || isempty(optimize_b) - optimize_b = false; -end - -if ~exist('sn', 'var') || isempty(sn) - if optimize_b - [b, sn] = estimate_baseline_noise(y); - else - [~, sn] = estimate_baseline_noise(y-smooth(y,100)); - end -end -if ~exist('optimize_g', 'var') || isempty(optimize_g) - optimize_g = 0; -end -if ~exist('decimate', 'var') || isempty(decimate) - decimate = 1; -else - decimate = max(1, round(decimate)); -end -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 10; -end -if ~exist('thresh_factor', 'var') || isempty(thresh_factor) - thresh_factor = 1.0; -end - -%% start from smin that avoid counting gaussian noise as a spike -smin = choose_smin(g, sn, 0.99999999); -thresh = thresh_factor* sn * sn * T; - -% change parameters due to downsampling -if decimate>1 - decimate = 1; %#ok - disp('to be done'); - % fluo = y; - % y = resample(y, 1, decimate); - % g = g^decimate; - % thresh = thresh / decimate / decimate; - % T = length(y); -end -g_converged = false; - -%% optimize parameters -tol = 1e-4; -if ~optimize_b %% don't optimize the baseline b - %% initialization - b = 0; - [solution, spks, active_set] = oasisAR2(y, g, [], smin); - - res = y - solution; - RSS0 = res' * res; - %% iteratively update parameters lambda & g - for miter=1:maxIter - if isempty(active_set) - break; - end - % update g - if miter==1 && and(optimize_g, ~g_converged); - g0 = g; - g = update_g(y-b, g, spks); - smin = choose_smin(g, sn, 0.9999); - [solution, spks,active_set] = oasisAR2(y, g, 0, smin); - if norm(g-g0,2)/norm(g0) < 1e-3 % g is converged - g_converged = true; - end - end - - res = y - solution; - RSS = res' * res; - if abs(RSS-RSS0)thresh, sum(solution)<1e-9) % constrained form has been found, stop - break; - else - RSS0 = RSS; - % update smin - [smin, solution, spks, active_set] = update_smin(y, g, smin,... - solution, spks, active_set, sqrt(thresh), max(spks)); - end - end -else - %% initialization - [b, ~] = estimate_baseline_noise(y); - [solution, spks, active_set] = oasisAR2(y-b, g, [], smin); - - res = y - solution -b; - RSS0 = res' * res; - %% iteratively update parameters lambda & g - for miter=1:maxIter - if isempty(active_set) - break; - end - % update g - if and(optimize_g, ~g_converged); - g0 = g; - g = update_g(y-b, g, spks); - smin = choose_smin(g, sn, 0.9999); - [solution, spks,active_set] = oasisAR2(y, g, 0, smin); - - if norm(g-g0,2)/norm(g0) < 1e-3 % g is converged - g_converged = true; - end - end - - res = y - solution -b; - RSS = res' * res; - if abs(RSS-RSS0)thresh, sum(solution)<1e-9) % constrained form has been found, stop - break; - else - RSS0 = RSS; - % update smin - [smin, solution, spks, active_set] = update_smin(y-b, g, smin,... - solution, spks, active_set, sqrt(thresh), max(spks)); - b = mean(y-solution); - end - end -end -c = solution; -s = spks; -g = g(1:2); - -%% nested functions - function [smin, solution, spks, active_set] = update_smin(y, g, smin, solution, ... - spks, active_set, thresh, s_max) - %%estimate smin to match the thresholded RSS - len_active_set = size(active_set, 1); - sv = linspace(smin, s_max, min(9, len_active_set)); - ind_start = 1; - ind_end = length(sv); - - while (ind_end-ind_start)>1 - ind = floor((ind_start+ind_end)/2); - tmp_smin = sv(ind); - [tmp_solution, tmp_spks, tmp_active_set] = oasisAR2(y, g, [], ... - tmp_smin, [], [], active_set); - sqRSS = norm(y-tmp_solution,2); - if sqRSSthresh % decrease smin - ind_end = ind; - else - break; - end - end - end - - -end -% -% function [c, active_set, g, s] = update_g(y, g, spks, smin, c) -% %% update the AR coefficient: g -% -% -% %% residual -% yres = y - c; -% T = length(y); -% %% convolution kernel -% ht = filter(1,[1,-g],[1,zeros(1,500)]); -% ht(ht<0.01) = []; -% w = length(ht); -% ht = [ zeros(1, 2), ht]; -% %% find all spikes -% tsp = find(spks>0); -% tsp(tsp<3) = []; -% tsp(tsp==T) = []; -% spv = spks(tsp); -% -% -% %% compute the mean waveform -% mean_trace = zeros(1, 2+w); -% for m=1:length(tsp) -% ti = tsp(m); -% if ti<= T-w -% mean_trace = mean_trace + ht*spv(m) + yres((ti-2):(ti+w-1))' ; -% else -% ind = (ti-2):T; -% mean_trace(1:(T-ti+3)) = mean_trace(1:(T-ti+3)) + ht(1:(T-ti+3))*spv(m) + yres(ind)'/spv(m); -% end -% end -% -% g = estimate_time_constant(mean_trace); -% [c, s, active_set] = oasisAR2(y, g, [], smin); -% end - -%update the AR coefficient: g -function g = update_g(y, g, spks) -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% g: 2x1 vector, AR2 parameters -% active_set: npools*4 matrix, previous active sets. -% smin: scalr, minimize size of nonzero spikes - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% initialization -s_th = quantile(spks(spks>1e-3), 0.25); -tsp = find(spks>=s_th); -tsp = reshape(tsp, 1, []); -time_p = find(conv2(double(spks<=s_th), ones(30,1), 'same')>0); -time_p = reshape(time_p,[],1); -y = reshape(y,[],1); % fluorescence data -yp = y(time_p); -T = length(y); -tau_dr = ar2exp(g); -tau_d = tau_dr(1); -tau_r = tau_dr(2); -warning('off', 'MATLAB:singularMatrix'); - -%% find the optimal g and get the warm started active_set -tau_d0 = tau_d; -tau_r0 = tau_r; -bnd_d = tau_d0 * [1/4, 4]; -bnd_r = tau_r0 * [1/4, 4]; -for m=1:10 - try - tau_r = fminbnd(@rss_taur, bnd_r(1), bnd_r(2)); - tau_d = fminbnd(@rss_taud, bnd_d(1), bnd_d(2)); - catch - break; - end - if and(abs(tau_d-tau_d0)/tau_d0 < 1e-4, abs(tau_r-tau_r0)/tau_r0 < 1e-4) - break; - else - tau_d0 = tau_d; - tau_r0 = tau_r; - end -end - -%% compute the optimal solution -g = exp2ar([tau_d, tau_r]); - -%% nested functions - - function rss = rss_taur(tau_r) - ht = (exp(-(1:T)/tau_d) - exp(-(1:T)/tau_r))/(tau_d-tau_r); - ht(T) = 0; - ind = bsxfun(@minus, time_p, tsp); - ind(ind<=0) = T; - V = ht(ind); - - % find the best value of st - s = (V'*V)\(V'*yp); - res = yp - V*s; - rss = res' * res; - end - - function rss = rss_taud(tau_d) - ht = (exp(-(1:T)/tau_d) - exp(-(1:T)/tau_r))/(tau_d-tau_r); - ht(T) = 0; - ind = bsxfun(@minus, time_p, tsp); - ind(ind<=0) = T; - V = ht(ind); - - % find the best value of st - s = (V'*V)\(V'*yp); - res = yp - V*s; - rss = res' * res; - end -end \ No newline at end of file diff --git a/deconvolveCa/oasis/update_g.m b/deconvolveCa/oasis/update_g.m deleted file mode 100644 index c28ba80..0000000 --- a/deconvolveCa/oasis/update_g.m +++ /dev/null @@ -1,83 +0,0 @@ -function [c, active_set, g, s] = update_g(y, active_set, g, lam) -%% update the tuning parameter lambda to reduce |s|_1 while |y-c|_2^2 <= sn^2*T - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities -%withone entry per time-bin. -% active_set: npools*4 matrix, previous active sets -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... -%impulse response. -% lam: scalar, curret value of sparsity penalty parameter lambda. - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% g: scalar - -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -%% initialization -len_active_set = size(active_set, 1); %number of active sets -y = reshape(y,[],1); % fluorescence data -maxl = max(active_set(:, 4)); % maximum ISI -c = zeros(size(y)); % the optimal denoised trace - -%% find the optimal g and get the warm started active_set -g = fminbnd(@rss_g, 0, 1); -yp = y - lam*(1-g); -for m=1:len_active_set - tmp_h = exp(log(g)*(0:maxl)'); % response kernel - tmp_hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - li = active_set(m, 4); - ti = active_set(m, 3); - idx = ti:(ti+li-1); - active_set(m,1) = (yp(idx))'*tmp_h(1:li); - active_set(m,2) = tmp_hh(li); -end -[c,s,active_set] = oasisAR1(y, g, lam, [], active_set); - -%% nested functions - function rss = rss_g(g) - h = exp(log(g)*(0:maxl)'); % response kernel - hh = cumsum(h.*h); % hh(k) = h(1:k)'*h(1:k) - yp = y - lam*(1-g); % include the penalty term - for ii=1:len_active_set - li = active_set(ii, 4); - ti = active_set(ii, 3); - idx = ti:(ti+li-1); - tmp_v = max(yp(idx)' * h(1:li) / hh(li), 0); - c(idx) = tmp_v*h(1:li); - end - res = y-c; - rss = res'*res; % residual sum of squares - end -end - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/oasis/update_kernel_exp2.m b/deconvolveCa/oasis/update_kernel_exp2.m deleted file mode 100644 index 991e3b9..0000000 --- a/deconvolveCa/oasis/update_kernel_exp2.m +++ /dev/null @@ -1,131 +0,0 @@ -function [kernel, s] = update_kernel_exp2(y, s, kernel) -%% estimate convolution kernel with the form of exp(-t/tau_d)-exp(-t/tau_r) - -%% inputs: -% y: 1 X T vector, observed fluorescence trace -% s: 1 X T vector, spike counts -% kernel: struct variable with fields {'type', 'fhandle', 'pars', -% 'nMax', 'lb', 'ub'}, it determines the parametric convolution kernel -% nMax: scalar, length of the convolution kernel -% lb: 2 X 1 vector, lower bounds of tau_d and tau_r -% ub: 2 X 1 vector, upper bounds of tau_d and tau_r -%% outputs: -% kernel: same as input -% s: optimal spike train -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -if ~exist('kernel', 'var') || isempty(kernel) - kernel = create_kernel('exp2'); -elseif ~strcmpi(kernel.type, 'exp2') - kernel = create_kernel('exp2'); - kernel.nMax = kernel.nMax; -end - -bound_pars = kernel.bound_pars; -if bound_pars - lb = kernel.lb; - ub = kernel.ub; -else - lb = kernel.pars/2; - ub = kernel.pars*2; -end -nMax = kernel.nMax; -fhandle = kernel.fhandle; - -t = 1:nMax; -T = length(y); %number of frames -y = reshape(y, T, 1); % observed fluorescence -s = reshape(s, T, 1); % spike counts - -%% create regression matrix -sind = reshape(find(s), 1, []); % indices of all spikes -nspk = length(sind); % number of vents -if nspk<2 % no events, stop running - return; -end -temp = bsxfun(@plus, (0:(nMax-1))', sind); % frames that are affected by s -ind = (temp<=T); % remove frames -[ind_tau, ind_s] = find(ind); %ind_tau corresponds to tau=(t-t'+1); ind_s corresponds to t'; t' is the spike time -yind = temp(ind(:)); -temp = sparse(yind, ind_s, ind_tau, T, nspk); % tmtp: t-t' -ind_nonzero = (sum(temp,2)>0); % choose frames affected by s -yv = y(ind_nonzero); -ny = length(yv); % number of frames used -temp = temp(ind_nonzero, :); -[rsub, csub, tmtp] = find(temp); - -%% find the optimal solution by shrinking the searching area -K = 5; -s_all = zeros(K, K, length(sind)); -% min_tau1 = lb(1); -% max_tau1 = ub(1); -% min_tau2 = lb(2); -% max_tau2 = ub(2); -f0 = inf; -thresh = 1e-3; -warning('off','MATLAB:nearlySingularMatrix') -warning('off','MATLAB:singularMatrix') -while true - tau_1 = linspace(lb(1), ub(1), K); - tau_2 = linspace(lb(2), ub(2), K); - rss = inf(K); - - for m=1:K - tau_d = tau_1(m); - for n=1:K - tau_r = tau_2(n); - if tau_r>tau_d - break; - end - gt = fhandle([tau_d, tau_r], t); - H = sparse(rsub, csub, gt(tmtp), ny, nspk); - sv = (H'*H)\(H'*yv); - s_all(m, n, :) = sv; - rss(m, n) = norm(H*sv-yv, 2); - end - end - - f1 = min(rss(:)); % new residual - [indr, indc] = find(rss==f1, 1); - if (f0-f1)/f1 < thresh %improvement is small - break; - elseif bound_pars % shrink the searching area and parameters are bounded - f0 = f1; - lb(1) = tau_1(max(1, indr-1)); - ub(1) = tau_1(min(K, indr+1)); - lb(2) = tau_2(max(1, indc-1)); - ub(2) = tau_2(min(K, indc+1)); - else % searching areas are not bounded - f0 = f1; - if indr==1 - lb(1) = lb(1)/2; - ub(1) = tau_1(2); - elseif indr==K - lb(1) = tau_1(K-1); - ub(1) = ub(1)*2; - else - lb(1) = tau_1(indr-1); - ub(1) = tau_1(indr+1); - end - - if indc==1 - lb(2) = lb(2)/2; - ub(2) = tau_2(2); - elseif indc==K - lb(2) = tau_2(K-1); - ub(2) = ub(2)*2; - else - lb(2) = tau_2(indc-1); - ub(2) = tau_2(indc+1); - end - - end -end -warning('on','MATLAB:nearlySingularMatrix') -warning('on','MATLAB:singularMatrix') -sv = squeeze(s_all(indr, indc, :)); -s(sind) = sv; -kernel.pars = [tau_1(indr), tau_2(indc)]; -kernel.fhandle = fhandle; -kernel.nMax = nMax; -end \ No newline at end of file diff --git a/deconvolveCa/oasis/update_lam.m b/deconvolveCa/oasis/update_lam.m deleted file mode 100644 index 76557fc..0000000 --- a/deconvolveCa/oasis/update_lam.m +++ /dev/null @@ -1,78 +0,0 @@ -function [c, active_set, lam, s, flag_lam] = update_lam(y, c, active_set, g, lam, thresh) -%% update the tuning parameter lambda to reduce |s|_1 while |y-c|_2^2 <= sn^2*T - -%% inputs: -% y: T*1 vector, One dimensional array containing the fluorescence intensities - %withone entry per time-bin. -% c: T*1 vector, previous c -% active_set: npools*4 matrix, previous active sets -% g: scalar, Parameter of the AR(1) process that models the fluorescence ... - %impulse response. -% lam: scalar, curret value of sparsity penalty parameter lambda. -% thresh: maximum residual sn*T^2 - -%% outputs -% c: T*1 vector -% s: T*1 vector, spike train -% active_set: npool x 4 matrix, active sets -% lam: scalar, new tuning parameter -% flag_lam: bool, True if it update lam with success -%% Authors: Pengcheng Zhou, Carnegie Mellon University, 2016 -% ported from the Python implementation from Johannes Friedrich - -%% References -% Friedrich J et.al., NIPS 2016, Fast Active Set Method for Online Spike Inference from Calcium Imaging - -c = reshape(c, [],1); -y = reshape(y, [],1); -len_active_set = size(active_set,1); - -res = y - c; -RSS = res'*res; - -temp = zeros(size(c)); -for ii=1:len_active_set - ti = active_set(ii, 3); - li = active_set(ii, 4); - idx = 0:(li-1); - temp(ti+idx) = (1-g^li)/ active_set(ii,2) * g.^(idx); -end - -aa = temp'*temp; -bb = res'*temp; -cc = RSS-thresh; -ll = (-bb + sqrt(bb^2-aa*cc)) / aa; -if imag(ll)~=0 - flag_lam = false; - s = [0; c(2:end)-c(1:(end-1))*g]; - return; -else - flag_lam = true; -end -lam = lam + ll; - -active_set(:,1) = active_set(:,1) - ll*(1-g.^active_set(:,4)); -[c, s, active_set] = oasisAR1(y, g, lam, 0, active_set); - - - - - - - - - - - - - - - - - - - - - - - diff --git a/deconvolveCa/oasis/update_tau.m b/deconvolveCa/oasis/update_tau.m deleted file mode 100644 index 7ae9a8a..0000000 --- a/deconvolveCa/oasis/update_tau.m +++ /dev/null @@ -1,144 +0,0 @@ -function [pars, s] = update_tau(y, s, pars, nspk) -%% estimate convolution kernel with the form of exp(-t/tau_d)-exp(-t/tau_r) - -%% inputs: -% y: 1 X T vector, observed fluorescence trace -% s: 1 X T vector, spike counts -% pars: struct variable with fields {'fhandle', 'vals', 'nMax', 'lb', 'ub'}, -% it determines the parametric convolution kernel. -% vals: scalar, current value of the [tau_d, tau_r] -% nMax: scalar, length of the convolution kernel -% lb: 2 X 1 vector, lower bounds of tau_d and tau_r -% ub: 2 X 1 vector, upper bounds of tau_d and tau_r -% bound_pars: boolean, bound the time constants or not -% 'nspk': scalar, number of spikes to be used for inferring the time -% constants - -%% outputs: -% kernel: same as input -% s: optimal spike train -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% initialization -vals = pars.vals; % current values of tau_d and tau_r -nMax = pars.nMax; % maximum length of the kernel - -t = 1:nMax; -T = length(y); %number of frames -y = reshape(y, [], 1); % raw calcium traces -s = reshape(s, [], 1); % estimated time constants - -if ~exist('nspk', 'var')||isempty(nspk) - nspk = 10; -end -[tsp, ~, spk_v] = find(s>0); % find the spike positions -v_thr = quantile(spk_v, 1-nspk/length(spk_v)); % find the thresholded value of chosing spikes for fitting spike trains -tsp_top = tsp(spk_v>=v_thr); -s(tsp_top) = 0; - -% compute the residual -kernel = exp2kernel(vals, (1:nMax)'); -c = conv(s, kernel); -y = y - c(1:T); % remove signals from the small spikes - - -bound_pars = pars.bound_pars; -if bound_pars - lb = pars.lb; - ub = pars.ub; -else - lb = pars.vals/2; - ub = pars.vals*2; -end - -%% create regression matrix -sind = reshape(tsp_top, 1, []); % indices of all spikes -nspk = length(sind); % number of vents -if nspk<2 % no events, stop running - return; -end -temp = bsxfun(@plus, (0:(nMax-1))', sind); % frames that are affected by s -ind = (temp<=T); % remove invalid frames -[ind_tau, ind_s] = find(ind); %ind_tau corresponds to tau=(t-t'+1); ind_s corresponds to t'; t' is the spike time -yind = temp(ind(:)); -temp = sparse(yind, ind_s, ind_tau, T, nspk); % tmtp: t-t' -ind_nonzero = (sum(temp,2)>0); % choose frames affected by s -yv = y(ind_nonzero); -ny = length(yv); % number of frames used -temp = temp(ind_nonzero, :); -[rsub, csub, tmtp] = find(temp); - -%% find the optimal solution by shrinking the searching area -K = 5; -s_all = zeros(K, K, length(sind)); -% min_tau1 = lb(1); -% max_tau1 = ub(1); -% min_tau2 = lb(2); -% max_tau2 = ub(2); -f0 = inf; -thresh = 1e-3; -warning('off','MATLAB:nearlySingularMatrix') -warning('off','MATLAB:singularMatrix') -while true - tau_1 = linspace(lb(1), ub(1), K); - tau_2 = linspace(lb(2), ub(2), K); - rss = inf(K); - - for m=1:K - tau_d = tau_1(m); - for n=1:K - tau_r = tau_2(n); - if tau_r>tau_d - break; - end - gt = exp2kernel([tau_d, tau_r], t); - H = sparse(rsub, csub, gt(tmtp), ny, nspk); - sv = (H'*H)\(H'*yv); - s_all(m, n, :) = sv; - rss(m, n) = norm(H*sv-yv, 2); - end - end - - f1 = min(rss(:)); % new residual - [indr, indc] = find(rss==f1, 1); - if (f0-f1)/f1 < thresh %improvement is small - break; - elseif bound_pars % shrink the searching area and parameters are bounded - f0 = f1; - lb(1) = tau_1(max(1, indr-1)); - ub(1) = tau_1(min(K, indr+1)); - lb(2) = tau_2(max(1, indc-1)); - ub(2) = tau_2(min(K, indc+1)); - else % searching areas are not bounded - f0 = f1; - if indr==1 - lb(1) = lb(1)/2; - ub(1) = tau_1(2); - elseif indr==K - lb(1) = tau_1(K-1); - ub(1) = ub(1)*2; - else - lb(1) = tau_1(indr-1); - ub(1) = tau_1(indr+1); - end - - if indc==1 - lb(2) = lb(2)/2; - ub(2) = tau_2(2); - elseif indc==K - lb(2) = tau_2(K-1); - ub(2) = ub(2)*2; - else - lb(2) = tau_2(indc-1); - ub(2) = tau_2(indc+1); - end - - end -end -warning('on','MATLAB:nearlySingularMatrix') -warning('on','MATLAB:singularMatrix') -sv = squeeze(s_all(indr, indc, :)); -s(tsp_top) = sv; -pars.vals = [tau_1(indr), tau_2(indc)]; -pars.nMax = nMax; -end \ No newline at end of file diff --git a/deconvolveCa/oasis_kernel/choose_smin.m b/deconvolveCa/oasis_kernel/choose_smin.m deleted file mode 100644 index 1fd55eb..0000000 --- a/deconvolveCa/oasis_kernel/choose_smin.m +++ /dev/null @@ -1,42 +0,0 @@ -function smin = choose_smin(kernel,sn,prob) -%% Choose minimal spike spike to enforce sparsity constraint in spike inference -% The function chooses a regularization weight for sparse deconvolution -% with a given kernel and noise level. The weight of the regularizer -% is chosen such that noise alone cannot lead to a non-zero solution is -% at least prob. - -% Inputs: -% kernel: deconvolution kernel -% if length(kernel) == 1 or length(kernel) == 2, then kernel -% is treated as a set of discrete time constants g. Otherwise, -% it is treated as the actual vector. -% sn: noise level -% prob: probability of zero solution (deafult: 0.99) - -% Output: -% smin: minimal spike size - -% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -% modified from choose_lambda.m Eftychios A. Pnevmatikakis, 2016, Simons Foundation -% based on ideas and discussions with J. Tubiana and G. Debregeas, -% Laboratorie Jean Parrin, UPMC, France - -% Reference for this approach: -% Selesnick, I. (2012). Sparse deconvolution (an MM algorithm) - -%% - -if nargin < 3 || isempty(prob) - prob = 0.9999; -end - -if nargin < 2 || isempty(sn) - sn = 1; - warning('Noise value not provided. Using sn = 1...') -end - -if length(kernel) <= 2 - kernel = filter(1,[1,-kernel(:)'],[1,zeros(1,999)]); -end - -smin = sn/norm(kernel)*norminv(prob); \ No newline at end of file diff --git a/deconvolveCa/oasis_kernel/create_kernel.m b/deconvolveCa/oasis_kernel/create_kernel.m deleted file mode 100644 index 254de2e..0000000 --- a/deconvolveCa/oasis_kernel/create_kernel.m +++ /dev/null @@ -1,83 +0,0 @@ -function kernel = create_kernel(kernel_type, pars, nMax, lb, ub, bound_pars) -%% create convolution kernel -%% inputs: -% kernel_type: string, convolution kernel type. now support {'exp', -% 'exp2', 'vector'} -% pars: parameters for the selected kernel type -% nMax: length of the kernel -% lb: lower bound for each parameter -% ub: upper bound for each parameter -% bound_pars: logical variable, bound the parameters or not {1, 0} -%% outputs -% kernel: struct variable - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -%% kernel size -if ~exist('nMax', 'var') || isempty(nMax) - nMax = 50; -end -kernel.nMax = nMax; - -%% initialize kernel -if ~exist('kernel_type', 'var') || isempty(kernel_type) - kernel_type = 'exp2'; -end -if strcmpi(kernel_type, 'exp') - % single exponential function: ~ exp(-t/tau) - kernel.type = 'exp'; - % parameter - if ~exist('pars', 'var') || isempty(pars) - kernel.pars = [5, .1]; - else - kernel = kernel.pars; - end - % function handle - kernel.fhandle = @(pars, t) exp(-t/pars) * (1-exp(-1/pars)) ... - / (1-exp(-nMax/pars)); -elseif strcmpi(kernel_type, 'vector') - % single vector - kernel.type = 'vector'; - % parameter - if ~exist('pars', 'var') || isempty(pars) - kernel.pars = exp(-(1:nMax)/10); - else - kernel.pars = pars; - end - % function handle - kernel.fhandle = @(pars, t) pars/sum(pars); -else - % differencing of two exponential function: - % ~ exp(-t/tau_d)-exp(-t/tau_r) - kernel.type = 'exp2'; - - % parameters - if ~exist('pars', 'var') || isempty(pars) - kernel.pars = [10, 1]; - else - kernel.pars = pars; - end - % function handle - kernel.fhandle = @(pars, t) (exp(-t/pars(1)) - exp(-t/pars(2))) ... - /( (1-exp(-nMax/pars(1)))/(1-exp(-1/pars(1))) ... - - (1-exp(-nMax/pars(2)))/(1-exp(-1/pars(2)))); -end - -% lower and upper bounds for parameters -if ~exist('lb', 'var') || isempty(lb) - kernel.lb = 0.5*kernel.pars; -else - kernel.lb = lb; -end -if ~exist('ub', 'var') || isempty(ub) - kernel.ub = 2*kernel.pars; -else - kernel.ub = ub; -end - -% bound the parameters of not -if ~exist('bound_pars', 'var')||isempty(bound_pars) - kernel.bound_pars = false; -else - kernel.bound_pars = bound_pars; -end \ No newline at end of file diff --git a/deconvolveCa/oasis_kernel/deconvCa.m b/deconvolveCa/oasis_kernel/deconvCa.m deleted file mode 100644 index 044cf81..0000000 --- a/deconvolveCa/oasis_kernel/deconvCa.m +++ /dev/null @@ -1,358 +0,0 @@ -function [c, s, kernel, iter] = deconvCa(y, kernel, smin, fit_gt, debug_on, sn, maxIter, theta, lambda) -%% deconvolve calcium traces to infer spike counts -%% inputs: -% y: 1*T vector, observed calcium traces -% kernel: struct variable with two fields {'fhandle', 'pars', nMax}. kernel -% deterines the convolution kernel -% fhandle: function handle, the function form of the response function -% pars: p*1 vector, parameters for fhandle -% nMax: scalar, maximum number of frames required by calcium indicators -% to return resting states -% smin: scalar, minimum number of nonzero spike count within each bin -% fit_gt: true or false. iteratively fit gt or not -% debug_on: play and save video of the whole procedure. -% sn: noise power -% maxIter: scalar, maximum iterations for running OASIS, default (3) -% theta: 1*T vecotr, weight vector at each time point -% lambda: scalar, tuning parameter - -%% outputs: -% c: 1*T vector, inferred calcium trace -% s: 1*T vector, inferred spike train -% kernel: convolution kernel -% iters: number of iterations for updating irf - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -% This work is based on one NIPS paper by Johannes Friedrich & Liam -% Paninski - -%% input arugments -y = reshape(y, 1, []); % convert data into row vector -if ~exist('sn', 'var') || isempty(sn) - sn = get_noise_fft(y); -end -T = length(y); % number of frames - -% get convolution kernel -if ~exist('kernel', 'var') || isempty(kernel) - kernel = create_kernel('exp2', ar2exp(estimate_time_constant(y,2))); -end -fhandle = kernel.fhandle; -nMax = kernel.nMax; - -y = [y, zeros(1, nMax)]; % add few more elements for computation convenience - -% threshold of the spike -if ~exist('smin', 'var') || isempty(smin) - smin = 3*sn; % min spike count -else - smin = smin * sn; -end - -% fit response function or not -if ~exist('fit_gt', 'var') || isempty(fit_gt) - fit_gt = false; -else - kernel.pars = ar2exp(estimate_time_constant(y,2)); -end -thresh = 1e-3; - -% debug mode -if ~exist('debug_on', 'var') || isempty(debug_on) - debug_on = false; -end - -% maximum iterations for running OASIS -if ~exist('maxIter', 'var') || isempty(maxIter) - maxIter = 5; -end - -% tuning parameter for enforcing sparsity -if ~exist('lambda', 'var') || isempty(lambda) - lambda = 0; % tuning parameter -end - -% weight for each frame -if ~exist('theta', 'var')|| isempty(theta) || (length(theta)==1) % weight vector - theta = ones(1, T); -elseif length(theta)==T - theta = reshape(theta, 1, T); -else - disp('elements in theta should be equal to elements in y'); - return; -end - -% tuning parameter for enforcing sparsity -if ~exist('lambda', 'var') || isempty(lambda) - lambda = 0; % tuning parameter -end - -%% running OASIS -if debug_on - figure('position', [1, 1 1500, 250]); - plot(y); hold on; - a = plot(y, 'r'); - avi_file = VideoWriter('example.avi'); - avi_file.open(); - xlim([1, T]); -end - -f0 = inf; % objective function -y0 = y; % backup the raw trace -iter = 1; % iteratiosn -for iter = 1:maxIter - if debug_on - title(sprintf('Iter %d, norm(residual) = %.4f', iter, f0)); - end - % normalize gt to make its maximum value to be 1 - gt = fhandle(kernel.pars, 1:nMax); % 1*nMax, response function of calcium transients - ind0 = 1; %correct the response function of the first event - gt = [reshape(gt, 1, nMax), zeros(1, T)]; % add few more elements to gt for computation convenience - - gt_max = max(gt); - gt = gt/gt_max; - gt1 = [gt(ind0:end), zeros(1, ind0-1)]; % kernel for the first frame - - %% initialize values for the results - s = zeros(size(y)); % spike count within each bin - v = zeros(size(y)); % sum(theta_t*y_t) - lambda - w = zeros(size(y)); % sum(theta_t^2 * g(t-ti+1)^2)) - pool_ti = zeros(size(y)); % first frame of each pool - - % initialize the first pool - v(1) = theta(1)*y(1)*gt1(1) - lambda; - w(1) = (theta(1)*gt1(1))^2; - s(1) = max(0, v(1) / w(1)); - % if s(1)=nMax % no influences from the previous events - vi = theta(t)*y(t)*gt(1) - lambda; - elseif tpre>1 % estimate vi and subtract the effect of the previous event - vi = theta(t) * (y(t)-s(tpre)*gt(t-tpre+1)) * gt(1) - lambda; - else % special treatment with the first event - vi = theta(t) * (y(t)-s(tpre)*gt1(t-tpre+1)) * gt(1) - lambda; - end - wi = (theta(t) * gt(1))^2; - si = vi/wi; - - % check the violatoin of si - if si>smin && frame_valid % no violation, create a new pool to save the result and move to the next new pool - % peel off the previous event - if (t-tpre)1 - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) - s(tpre)*gt(1:nMax); - else - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) - s(tpre)*gt1(1:nMax); - end - end - pool_ti(ii) = t; % create a new pool - tpre = t; - v(t) = vi; - w(t) = wi; - s(t) = si; - ii = ii+1; % move to the next pool - t = t+1; - else % with violation - frame_valid = true; % allows the next frame to be valid - if (t-tpre)>=nMax - % ignore this frame directly and move to the next frame - t = t + 1; - continue; - elseif tpre>1 % merge it to the current pool - v(tpre) = v(tpre) + theta(t)*y(t)*gt(t-tpre+1); - w(tpre) = w(tpre) + (theta(t)*gt(t-tpre+1))^2; - else - v(tpre) = v(tpre) + theta(t)*y(t)*gt1(t-tpre+1); - w(tpre) = w(tpre) + (theta(t)*gt1(t-tpre+1)); - end - s(tpre) = v(tpre)/w(tpre); % update the current event - - % check the violation of the current pool - if s(tpre)>smin % the previous event is still avaiable - t = t+1; - continue; - elseif ii==2 %the previous pool is not available anymore, but it's the first pool - s(tpre) = max(0, s(tpre)); - t = t+1; - else % not available, then delete the current pool and force its first frame to be - % event-free. - t = tpre; % go back to the first frame of the current pull - - frame_valid = false; % force the frame t to be invalid - ii = ii-1; - tpre = pool_ti(ii-1); - - % add back the signal of the previous pool - if (t-tpre)>nMax - t = t+1; - frame_valid = true; - continue; - elseif tpre>1 - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) + s(tpre)*gt(1:nMax); - else - y(tpre+(1:nMax)-1) = y(tpre+(1:nMax)-1) + s(tpre)*gt1(1:nMax); - end - end - end - end - %% collect the results - pool_ti(ii:end) = []; - temp = s(pool_ti); - s = zeros(1, T); - s(pool_ti) = temp; - temp = s; - temp(1) = 0; - c = conv(temp, gt(1:nMax)); - c = c(1:T) + s(1)*gt1(1:T); - f1 = norm(y(1:T)-c, 2); - s = s*sum(gt); - if debug_on - delete(a); - a = plot(c, 'r'); - drawnow(); - temp = getframe(); - temp.cdata = imresize(temp.cdata, [200, 1500]); - avi_file.writeVideo(temp); - end - - %% break the while loop - if ~fit_gt % don't iterate gt - break; - elseif (f0-f1)/f0 <= thresh % improvement is small, stop - break; - else % move to the next iteration - y = y0; - if strcmpi(kernel.type, 'exp2') - [kernel, ~] = update_kernel_exp2(y(1:T), s, kernel); - else - break; - end - f0 = f1; - iter = iter + 1; - % return; - end -end - -if debug_on - avi_file.close(); - close(gcf); -end -end - -%% estimate the noise power -function [sn,psdx,ff] = get_noise_fft(Y,options) -% Written by: -% Eftychios A. Pnevmatikakis, Simons Foundation, 2015 -% with minor adaption by Pengcheng Zhou, Carnegie Mellon University, 2015 -options.noise_range = [.25, .5]; -range_ff = options.noise_range; -options.noise_method = 'logmexp'; -method = options.noise_method; -options.block_size = [64, 64]; -block_size = options.block_size; -options.split_data = false; -split_data = options.split_data; -options.max_timesteps = 3000; - -dims = ndims(Y); -sizY = size(Y); -N = min(sizY(end),options.max_timesteps); -if N < sizY(end) - %Y = reshape(Y,prod(sizY(1:end-1)),[]); - Y(prod(sizY(1:end-1))*N+1:end) = []; - Y = reshape(Y,[sizY(1:end-1),N]); -end - -Fs = 1; -ff = 0:Fs/N:Fs/2; -indf=ff>range_ff(1); -indf(ff>range_ff(2))=0; -if dims > 1 - d = prod(sizY(1:dims-1)); - Y = reshape(Y,d,N); - Nb = prod(block_size); - SN = cell(ceil(d/Nb),1); - PSDX = cell(ceil(d/Nb),1); - if ~split_data - for ind = 1:ceil(d/Nb); - xdft = fft(Y((ind-1)*Nb+1:min(ind*Nb,d),:),[],2); - xdft = xdft(:,1: floor(N/2)+1); % FN: floor added. - psdx = (1/(Fs*N)) * abs(xdft).^2; - psdx(:,2:end-1) = 2*psdx(:,2:end-1); - %SN{ind} = mean_psd(psdx(:,indf),method); - switch method - case 'mean' - SN{ind}=sqrt(mean(psdx(:,indf)/2,2)); - case 'median' - SN{ind}=sqrt(median(psdx(:,indf)/2),2); - case 'logmexp' - SN{ind} = sqrt(exp(mean(log(psdx(:,indf)/2),2))); - end - PSDX{ind} = psdx; - end - else - nc = ceil(d/Nb); - Yc = mat2cell(Y,[Nb*ones(nc-1,1);d-(nc-1)*Nb],N); - parfor ind = 1:ceil(d/Nb); - xdft = fft(Yc{ind},[],2); - xdft = xdft(:,1:floor(N/2)+1); - psdx = (1/(Fs*N)) * abs(xdft).^2; - psdx(:,2:end-1) = 2*psdx(:,2:end-1); - Yc{ind} = []; - switch method - case 'mean' - SN{ind}=sqrt(mean(psdx(:,indf)/2,2)); - case 'median' - SN{ind}=sqrt(median(psdx(:,indf)/2),2); - case 'logmexp' - SN{ind} = sqrt(exp(mean(log(psdx(:,indf)/2),2))); - end - - end - end - sn = cell2mat(SN); -else - xdft = fft(Y); - xdft = xdft(:,1:floor(N/2)+1); - psdx = (1/(Fs*N)) * abs(xdft).^2; - psdx(:,2:end-1) = 2*psdx(:,2:end-1); - switch method - case 'mean' - sn = sqrt(mean(psdx(:,indf)/2,2)); - case 'median' - sn = sqrt(median(psdx(:,indf)/2),2); - case 'logmexp' - sn = sqrt(exp(mean(log(psdx(:,indf)/2),2))); - end -end -psdx = cell2mat(PSDX); -if dims > 2 - sn = reshape(sn,sizY(1:dims-1)); -end -end diff --git a/deconvolveCa/oasis_kernel/dsKernel.m b/deconvolveCa/oasis_kernel/dsKernel.m deleted file mode 100644 index 519fd76..0000000 --- a/deconvolveCa/oasis_kernel/dsKernel.m +++ /dev/null @@ -1,42 +0,0 @@ -function kernel_new = dsKernel(kernel, tsub) -%% downsample/upsample the convolution kernel -%% inputs: -% kernel: struct variable with fields {'kernel_type', 'pars', 'nMax', 'lb', 'ub', 'bound_pars'} -% kernel_type: string, convolution kernel type. now support {'exp', -% 'exp2', 'vector'} -% pars: parameters for the selected kernel type -% nMax: length of the kernel -% lb: lower bound for each parameter -% ub: upper bound for each parameter -% bound_pars: logical variable, bound the parameters or not {1, 0} -%% outputs -% kernel: struct variable - -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 - -kernel_new = kernel; -if nargin<2 || isempty(tsub) - return; -end - -%% kernel size -kernel_new.nMax = ceil(kernel.nMax/tsub); - -%% kernel type -kernel_type = kernel.type; -if strcmpi(kernel_type, 'exp') - % single exponential function: ~ exp(-t/tau) - kernel_new.pars = kernel.pars/tsub; -elseif strcmpi(kernel_type, 'vector') - % single vector -len_kernel = length(kernel.pars); - kernel_new.pars = resample(kernel.pars, ceil(len_kernel/tsub), len_kernel); -else - % differencing of two exponential function: - % ~ exp(-t/tau_d)-exp(-t/tau_r) - kernel_new.pars = kernel.pars/tsub; -end - -%% lower and upper bounds for parameters -kernel_new.lb = kernel.lb / tsub; -kernel_new.ub = kernel.ub / tsub; \ No newline at end of file diff --git a/deconvolveCa/oasis_kernel/test_oasis.m b/deconvolveCa/oasis_kernel/test_oasis.m deleted file mode 100644 index 6f888a6..0000000 --- a/deconvolveCa/oasis_kernel/test_oasis.m +++ /dev/null @@ -1,34 +0,0 @@ -%% function -clear; clc; close all; -T = 1000; -s = double(rand(1, T)>0.98); -sig = 0.04; - -% example -tau_d = 5; -tau_r = 1; -nMax = 100; -pars = [tau_d, tau_r]; -kernel = create_kernel('exp2', pars, nMax); - -t = 1:kernel.nMax; -gt = kernel.fhandle(kernel.pars, t); -c1 = conv(s, gt); -c1 = c1(1:T); -y1 = c1 + randn(1, T) * sig; - -%% use the true convolution kernel -kernel0 = kernel; -kernel0.pars = [10, 0.1]; -kernel0.bound_pars = false; -figure('position', [1,1,1500, 200]); -plot(y1); -hold on; -plot(c1, 'r', 'linewidth', 2); -plot(-s*0.1, 'r', 'linewidth', 2); -tic; -[chat, shat, kernel_fit, iters] = deconvCa(y1, kernel0, 2, true, false); -toc; -plot(chat,'-.g','linewidth', 2); -plot(-shat*0.1, '-.g', 'linewidth', 2); %, '-.'); -legend('data', 'ground truth: c','ground truth: s', 'OASIS:c', 'OASIS: s'); % 'gound truth: s', 'OASIS: c', 'OASIS: s'); \ No newline at end of file diff --git a/deconvolveCa/oasis_kernel/update_kernel_exp2.m b/deconvolveCa/oasis_kernel/update_kernel_exp2.m deleted file mode 100644 index 3d46768..0000000 --- a/deconvolveCa/oasis_kernel/update_kernel_exp2.m +++ /dev/null @@ -1,130 +0,0 @@ -function [kernel, s] = update_kernel_exp2(y, s, kernel) -%% estimate convolution kernel with the form of exp(-t/tau_d)-exp(-t/tau_r) - -%% inputs: -% y: 1 X T vector, observed fluorescence trace -% s: 1 X T vector, spike counts -% kernel: struct variable with fields {'type', 'fhandle', 'pars', -% 'nMax', 'lb', 'ub'}, it determines the parametric convolution kernel -% nMax: scalar, length of the convolution kernel -% lb: 2 X 1 vector, lower bounds of tau_d and tau_r -% ub: 2 X 1 vector, upper bounds of tau_d and tau_r -%% outputs: -% kernel: same as input -% s: optimal spike train -%% Author: Pengcheng Zhou, Carnegie Mellon University, 2016 -if ~exist('kernel', 'var') || isempty(kernel) - kernel = create_kernel('exp2'); -elseif ~strcmpi(kernel.type, 'exp2') - kernel = create_kernel('exp2'); - kernel.nMax = kernel.nMax; -end - -bound_pars = kernel.bound_pars; -if bound_pars - lb = kernel.lb; - ub = kernel.ub; -else - lb = kernel.pars/2; - ub = kernel.pars*2; -end -nMax = kernel.nMax; -fhandle = kernel.fhandle; - -t = 1:nMax; -T = length(y); %number of frames -y = reshape(y, T, 1); % observed fluorescence -s = reshape(s, T, 1); % spike counts - -%% create regression matrix -sind = reshape(find(s), 1, []); % indices of all spikes -nspk = length(sind); % number of vents -if nspk<2 % no events, stop running - return; -end -temp = bsxfun(@plus, (0:(nMax-1))', sind); % frames that are affected by s -ind = (temp<=T); % remove frames -[ind_tau, ind_s] = find(ind); %ind_tau corresponds to tau=(t-t'+1); ind_s corresponds to t'; t' is the spike time -yind = temp(ind(:)); -temp = sparse(yind, ind_s, ind_tau, T, nspk); % tmtp: t-t' -ind_nonzero = (sum(temp,2)>0); % choose frames affected by s -yv = y(ind_nonzero); -ny = length(yv); % number of frames used -temp = temp(ind_nonzero, :); -[rsub, csub, tmtp] = find(temp); - -%% find the optimal solution by shrinking the searching area -K = 5; -s_all = zeros(K, K, length(sind)); -% min_tau1 = lb(1); -% max_tau1 = ub(1); -% min_tau2 = lb(2); -% max_tau2 = ub(2); -f0 = inf; -thresh = 1e-3; -warning('off','MATLAB:nearlySingularMatrix') -warning('off','MATLAB:singularMatrix') -while true - tau_1 = linspace(lb(1), ub(1), K); - tau_2 = linspace(lb(2), ub(2), K); - rss = inf(K); - - for m=1:K - tau_d = tau_1(m); - for n=1:K - tau_r = tau_2(n); - if tau_r>tau_d - break; - end - gt = fhandle([tau_d, tau_r], t); - H = sparse(rsub, csub, gt(tmtp), ny, nspk); - sv = (H'*H)\(H'*yv); - s_all(m, n, :) = sv; - rss(m, n) = norm(H*sv-yv, 2); - end - end - - f1 = min(rss(:)); % new residual - [indr, indc] = find(rss==f1, 1); - if (f0-f1)/f1 < thresh %improvement is small - break; - elseif bound_pars % shrink the searching area and parameters are bounded - f0 = f1; - lb(1) = tau_1(max(1, indr-1)); - ub(1) = tau_1(min(K, indr+1)); - lb(2) = tau_2(max(1, indc-1)); - ub(2) = tau_2(min(K, indc+1)); - else % searching areas are not bounded - f0 = f1; - if indr==1 - lb(1) = lb(1)/2; - ub(1) = tau_1(2); - elseif indr==K - lb(1) = tau_1(K-1); - ub(1) = ub(1)*2; - else - lb(1) = tau_1(indr-1); - ub(1) = tau_1(indr+1); - end - - if indc==1 - lb(2) = lb(2)/2; - ub(2) = tau_2(2); - elseif indc==K - lb(2) = tau_2(K-1); - ub(2) = ub(2)*2; - else - lb(2) = tau_2(indc-1); - ub(2) = tau_2(indc+1); - end - - end -end -warning('on','MATLAB:nearlySingularMatrix') -warning('on','MATLAB:singularMatrix') -sv = squeeze(s_all(indr, indc, :)); -s(sind) = sv; -kernel.pars = [tau_1(indr), tau_2(indc)]; -kernel.fhandle = fhandle; -kernel.nMax = nMax; -end \ No newline at end of file diff --git a/deconvolveCa/setup.m b/deconvolveCa/setup.m deleted file mode 100644 index 01d8b0c..0000000 --- a/deconvolveCa/setup.m +++ /dev/null @@ -1,36 +0,0 @@ -oasis_folder = fileparts(mfilename('fullpath')); -addpath(sprintf('%s', oasis_folder)); -addpath(sprintf('%s%sfunctions', oasis_folder, filesep)); -addpath(sprintf('%s%soasis', oasis_folder, filesep)); -addpath(sprintf('%s%soasis_kernel', oasis_folder, filesep)); -addpath(sprintf('%s%sMCMC', oasis_folder, filesep)); -addpath(sprintf('%s%sMCMC%sutilities', oasis_folder, filesep, filesep)); - -%% install convex optimization solvers -optimization_folder = sprintf('%s%soptimization', oasis_folder, filesep); -if ~exist(optimization_folder, 'dir'); - mkdir(optimization_folder); -end - -% install cvx -if isempty(which('cvx_begin.m')) - if ~exist('cvx', 'dir') - %install cvx - if ismac - cvx_url = 'http://web.cvxr.com/cvx/cvx-maci64.zip'; - elseif isunix - cvx_url = 'http://web.cvxr.com/cvx/cvx-a64.zip'; - elseif ispc - cvx_url = 'http://web.cvxr.com/cvx/cvx-w64.zip'; - else - fprints('Your platform is not supported by CVX\n'); - return; - end - fprintf('Downloading CVX...\n'); - unzip(cvx_url, optimization_folder); - end - run(sprintf('%s%scvx%scvx_setup', optimization_folder, filesep, filesep)); -end - -%% save the current path -%savepath();