mc3 3.2.1__tar.gz → 3.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mc3-3.3.0/.github/workflows/python-package.yml +47 -0
- mc3-3.3.0/MANIFEST.in +12 -0
- {mc3-3.2.1 → mc3-3.3.0}/PKG-INFO +6 -24
- mc3-3.3.0/docs/docs_requirements.txt +6 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/get_started.rst +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/docs/index.rst +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/__init__.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/__main__.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/chain.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/fit_driver.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/mcmc_driver.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/plots/__init__.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/plots/colors.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/plots/plot_functions.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/plots/posterior.py +58 -23
- {mc3-3.2.1 → mc3-3.3.0}/mc3/sampler_driver.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/stats/__init__.py +3 -1
- mc3-3.3.0/mc3/stats/dwt.py +229 -0
- {mc3-3.2.1 → mc3-3.3.0}/mc3/stats/gelman.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/stats/prayer.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/stats/stats.py +78 -147
- mc3-3.3.0/mc3/stats/time_averaging.py +199 -0
- {mc3-3.2.1 → mc3-3.3.0}/mc3/utils/__init__.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/utils/log.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/utils/utils.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/mc3/version.py +3 -3
- {mc3-3.2.1 → mc3-3.3.0}/mc3.egg-info/PKG-INFO +6 -24
- {mc3-3.2.1 → mc3-3.3.0}/mc3.egg-info/SOURCES.txt +3 -15
- {mc3-3.2.1 → mc3-3.3.0}/mc3.egg-info/requires.txt +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/pyproject.toml +4 -4
- {mc3-3.2.1 → mc3-3.3.0}/requirements.txt +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/tests/test_fit.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/tests/test_logging.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/tests/test_mcmc.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/tests/test_plots.py +1 -1
- {mc3-3.2.1 → mc3-3.3.0}/tests/test_stats.py +39 -34
- {mc3-3.2.1 → mc3-3.3.0}/tests/test_utils.py +1 -1
- mc3-3.2.1/MANIFEST.in +0 -19
- mc3-3.2.1/Makefile +0 -46
- mc3-3.2.1/docs/figures/quad_bestfit.png +0 -0
- mc3-3.2.1/docs/figures/quad_fitting.png +0 -0
- mc3-3.2.1/docs/figures/quad_hist.png +0 -0
- mc3-3.2.1/docs/figures/quad_pairwise.png +0 -0
- mc3-3.2.1/docs/figures/quad_trace.png +0 -0
- mc3-3.2.1/docs/figures/rms-vs-binsize.png +0 -0
- mc3-3.2.1/mc3/stats/time_averaging.py +0 -60
- mc3-3.2.1/setup.py +0 -38
- mc3-3.2.1/src_c/_binarray.c +0 -107
- mc3-3.2.1/src_c/_chisq.c +0 -167
- mc3-3.2.1/src_c/_dwt.c +0 -216
- mc3-3.2.1/src_c/_time_averaging.c +0 -171
- mc3-3.2.1/src_c/include/ind.h +0 -9
- mc3-3.2.1/src_c/include/stats.h +0 -224
- mc3-3.2.1/src_c/include/wavelet.h +0 -128
- {mc3-3.2.1 → mc3-3.3.0}/.readthedocs.yml +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/CONTRIBUTING.md +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/LICENSE +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/README.md +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/Makefile +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/api.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/conf.py +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/contributing.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/fit_tutorial.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/license.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/make.bat +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/mcmc_tutorial.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/references.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/docs/time_averaging.rst +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/examples/get_started.py +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/examples/timeavg.py +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/examples/tutorial.py +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/mc3.egg-info/dependency_links.txt +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/mc3.egg-info/entry_points.txt +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/mc3.egg-info/top_level.txt +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/pytest.ini +0 -0
- {mc3-3.2.1 → mc3-3.3.0}/setup.cfg +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
|
2
|
+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
|
3
|
+
|
|
4
|
+
name: Tests
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ "*" ]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [ "main" ]
|
|
11
|
+
schedule:
|
|
12
|
+
- cron: '0 12 1 * *'
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
|
|
17
|
+
runs-on: ${{ matrix.os }}
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
22
|
+
os: [ubuntu-latest]
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v6
|
|
26
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
27
|
+
uses: actions/setup-python@v6
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install --upgrade pip
|
|
33
|
+
python -m pip install flake8 pytest
|
|
34
|
+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
|
35
|
+
|
|
36
|
+
- name: Install package
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install -e .
|
|
39
|
+
- name: Lint with flake8
|
|
40
|
+
run: |
|
|
41
|
+
# stop the build if there are Python syntax errors or undefined names
|
|
42
|
+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
|
43
|
+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
|
44
|
+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
|
45
|
+
- name: Test with pytest
|
|
46
|
+
run: |
|
|
47
|
+
pytest tests -v
|
mc3-3.3.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
include MANIFEST.in
|
|
2
|
+
include CONTRIBUTING.md
|
|
3
|
+
include README.md
|
|
4
|
+
include LICENSE
|
|
5
|
+
include pyproject.toml
|
|
6
|
+
include requirements.txt
|
|
7
|
+
include pytest.ini
|
|
8
|
+
include .readthedocs.yml
|
|
9
|
+
include .github/workflows/python-package.yml
|
|
10
|
+
include tests/*
|
|
11
|
+
include docs/*
|
|
12
|
+
include examples/*.py
|
{mc3-3.2.1 → mc3-3.3.0}/PKG-INFO
RENAMED
|
@@ -1,37 +1,19 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mc3
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Multi-core Markov-chain Monte Carlo package
|
|
5
5
|
Author-email: Patricio Cubillos <patricio.cubillos@oeaw.ac.at>
|
|
6
|
-
License:
|
|
7
|
-
|
|
8
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
-
in the Software without restriction, including without limitation the rights
|
|
11
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
-
furnished to do so, subject to the following conditions:
|
|
14
|
-
|
|
15
|
-
The above copyright notice and this permission notice shall be included in
|
|
16
|
-
all copies or substantial portions of the Software.
|
|
17
|
-
|
|
18
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
24
|
-
THE SOFTWARE.
|
|
25
|
-
|
|
6
|
+
License-Expression: MIT
|
|
26
7
|
Project-URL: Homepage, https://github.com/pcubillos/mc3
|
|
27
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.10
|
|
28
9
|
Description-Content-Type: text/markdown
|
|
29
10
|
License-File: LICENSE
|
|
30
|
-
Requires-Dist: numpy>=
|
|
11
|
+
Requires-Dist: numpy>=2.0.0
|
|
31
12
|
Requires-Dist: scipy>=1.5.4
|
|
32
13
|
Requires-Dist: matplotlib>=3.3.4
|
|
33
14
|
Provides-Extra: test
|
|
34
15
|
Requires-Dist: pytest>=6.0; extra == "test"
|
|
16
|
+
Dynamic: license-file
|
|
35
17
|
|
|
36
18
|
# mc3: Multi-core Markov-chain Monte Carlo
|
|
37
19
|
> A Python implementation of the Markov-chain Monte Carlo algorithm.
|
|
@@ -6,7 +6,7 @@ Getting Started
|
|
|
6
6
|
System Requirements
|
|
7
7
|
-------------------
|
|
8
8
|
|
|
9
|
-
``mc3`` is compatible with Python 3.
|
|
9
|
+
``mc3`` is compatible with Python 3.10+, and is `tested
|
|
10
10
|
<https://github.com/pcubillos/mc3/actions/workflows/python-package.yml>`_ to work on Unix/Linux and OS X machines.
|
|
11
11
|
|
|
12
12
|
Install
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2015-
|
|
1
|
+
# Copyright (c) 2015-2026 Patricio Cubillos and contributors.
|
|
2
2
|
# mc3 is open-source software under the MIT license (see LICENSE).
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
@@ -140,6 +140,8 @@ def _histogram(
|
|
|
140
140
|
hist_kw['facecolor'] = 'none'
|
|
141
141
|
|
|
142
142
|
for i in range(npars):
|
|
143
|
+
if np.any(np.isnan(posterior[:,i])):
|
|
144
|
+
continue
|
|
143
145
|
ax = axes[i]
|
|
144
146
|
if clear:
|
|
145
147
|
ax.clear()
|
|
@@ -533,6 +535,7 @@ class Marginal():
|
|
|
533
535
|
bins=25, fontsize=11, linewidth=1.5,
|
|
534
536
|
axes=None,
|
|
535
537
|
show_texts=True, show_estimates=True,
|
|
538
|
+
alpha=0.6,
|
|
536
539
|
):
|
|
537
540
|
self.source = source
|
|
538
541
|
self.fig = None
|
|
@@ -544,6 +547,7 @@ class Marginal():
|
|
|
544
547
|
self.bestp = bestp
|
|
545
548
|
self.ranges = ranges
|
|
546
549
|
self.theme = theme
|
|
550
|
+
self.alpha = alpha
|
|
547
551
|
|
|
548
552
|
if nx is None or ny is None:
|
|
549
553
|
# Default layout:
|
|
@@ -630,6 +634,7 @@ class Marginal():
|
|
|
630
634
|
hpd_min, self.source.low_bounds, self.source.high_bounds,
|
|
631
635
|
self.linewidth, self.theme,
|
|
632
636
|
self.orientation,
|
|
637
|
+
alpha=self.alpha,
|
|
633
638
|
top_pad=1.25,
|
|
634
639
|
)
|
|
635
640
|
_plot_marginal(self)
|
|
@@ -637,7 +642,7 @@ class Marginal():
|
|
|
637
642
|
if savefile is not None:
|
|
638
643
|
self.fig.savefig(savefile, dpi=300)
|
|
639
644
|
|
|
640
|
-
def overplot(self,
|
|
645
|
+
def overplot(self, posts, labels=None, nlevels=4, alpha=0.4, axes_mask=None):
|
|
641
646
|
"""
|
|
642
647
|
Overplot additional posteriors in the same figure.
|
|
643
648
|
|
|
@@ -659,25 +664,39 @@ class Marginal():
|
|
|
659
664
|
length of labels has to be one more than posts, because
|
|
660
665
|
it also contains the label for self.
|
|
661
666
|
"""
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
667
|
+
all_posts = [self.source] + list(posts)
|
|
668
|
+
for i,post in enumerate(posts):
|
|
669
|
+
estimates = post.estimates
|
|
670
|
+
if not self.show_estimates:
|
|
671
|
+
estimates = [None for _ in estimates]
|
|
665
672
|
hpd_min = None
|
|
673
|
+
if '_like' in self.statistics:
|
|
674
|
+
hpd_min = self.source.hpd_min
|
|
666
675
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
676
|
+
_histogram(
|
|
677
|
+
post.posterior, estimates, self.ranges,
|
|
678
|
+
self.hist_axes, self.bins,
|
|
679
|
+
post.pdf, post.xpdf,
|
|
680
|
+
hpd_min, post.low_bounds, post.high_bounds,
|
|
681
|
+
self.linewidth, post.theme,
|
|
682
|
+
post.orientation, alpha=alpha,
|
|
683
|
+
clear=False,
|
|
684
|
+
)
|
|
685
|
+
if not self.show_texts:
|
|
686
|
+
return
|
|
687
|
+
text_cols = [post.theme.color for post in all_posts]
|
|
688
|
+
for text in self.stats_texts:
|
|
689
|
+
text.set_visible(False)
|
|
690
|
+
self.stats_texts = []
|
|
670
691
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
self.
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
clear=False,
|
|
680
|
-
)
|
|
692
|
+
for j in range(self.npars):
|
|
693
|
+
stats_texts = [
|
|
694
|
+
'' if post.mask[j] else rf'{post.tex_estimates[j]}'
|
|
695
|
+
for post in all_posts
|
|
696
|
+
]
|
|
697
|
+
self.stats_texts += colors.rainbow_text(
|
|
698
|
+
self.hist_axes[j], stats_texts, self.fontsize, text_cols,
|
|
699
|
+
)
|
|
681
700
|
|
|
682
701
|
|
|
683
702
|
class Figure(Marginal):
|
|
@@ -694,10 +713,11 @@ class Figure(Marginal):
|
|
|
694
713
|
bins=25, nlevels=6, fontsize=None, linewidth=None,
|
|
695
714
|
show_texts=True, show_estimates=True,
|
|
696
715
|
show_colorbar=True,
|
|
716
|
+
figure=None,
|
|
697
717
|
fignum=None,
|
|
698
718
|
):
|
|
699
719
|
self.source = source
|
|
700
|
-
self.fig =
|
|
720
|
+
self.fig = figure
|
|
701
721
|
self.pair_axes = None
|
|
702
722
|
self.hist_axes = None
|
|
703
723
|
self.posterior = posterior
|
|
@@ -934,7 +954,7 @@ class Figure(Marginal):
|
|
|
934
954
|
post.posterior, estimates, self.ranges, self.hist_axes,
|
|
935
955
|
self.bins, post.pdf, post.xpdf,
|
|
936
956
|
hpd_min, post.low_bounds, post.high_bounds,
|
|
937
|
-
self.linewidth, post.theme, post.orientation, alpha=
|
|
957
|
+
self.linewidth, post.theme, post.orientation, alpha=alpha,
|
|
938
958
|
clear=False,
|
|
939
959
|
)
|
|
940
960
|
if not self.show_texts:
|
|
@@ -1044,7 +1064,7 @@ class StatisticsUpdate(ShareUpdate):
|
|
|
1044
1064
|
)
|
|
1045
1065
|
|
|
1046
1066
|
|
|
1047
|
-
class Posterior(
|
|
1067
|
+
class Posterior():
|
|
1048
1068
|
"""
|
|
1049
1069
|
Classification of posterior plotting tools.
|
|
1050
1070
|
|
|
@@ -1090,6 +1110,7 @@ class Posterior(object):
|
|
|
1090
1110
|
show_texts=True, show_estimates=True,
|
|
1091
1111
|
show_colorbar=True,
|
|
1092
1112
|
seed=314159,
|
|
1113
|
+
mask=None,
|
|
1093
1114
|
):
|
|
1094
1115
|
self.figures = []
|
|
1095
1116
|
nsamples, self.npars = np.shape(posterior)
|
|
@@ -1131,7 +1152,9 @@ class Posterior(object):
|
|
|
1131
1152
|
self.bestp = bestp
|
|
1132
1153
|
self.statistics = statistics
|
|
1133
1154
|
self.quantile = quantile
|
|
1134
|
-
|
|
1155
|
+
if mask is None:
|
|
1156
|
+
mask = np.ones(self.npars, bool)
|
|
1157
|
+
self.mask = mask
|
|
1135
1158
|
|
|
1136
1159
|
def plot(
|
|
1137
1160
|
self, plot_marginal=True,
|
|
@@ -1143,6 +1166,7 @@ class Posterior(object):
|
|
|
1143
1166
|
show_texts=None, show_estimates=None,
|
|
1144
1167
|
show_colorbar=None,
|
|
1145
1168
|
savefile=None,
|
|
1169
|
+
nlevels=None,
|
|
1146
1170
|
):
|
|
1147
1171
|
"""
|
|
1148
1172
|
Plot marginal histograms and pairwise posteriors.
|
|
@@ -1156,6 +1180,8 @@ class Posterior(object):
|
|
|
1156
1180
|
show_texts = self.show_texts
|
|
1157
1181
|
if show_colorbar is None:
|
|
1158
1182
|
show_colorbar = self.show_colorbar
|
|
1183
|
+
if nlevels is None:
|
|
1184
|
+
nlevels = 6
|
|
1159
1185
|
|
|
1160
1186
|
fig = Figure(
|
|
1161
1187
|
self,
|
|
@@ -1174,7 +1200,8 @@ class Posterior(object):
|
|
|
1174
1200
|
show_texts=show_texts,
|
|
1175
1201
|
show_estimates=show_estimates,
|
|
1176
1202
|
show_colorbar=show_colorbar,
|
|
1177
|
-
# bins=25,
|
|
1203
|
+
# bins=25,
|
|
1204
|
+
nlevels=nlevels,
|
|
1178
1205
|
)
|
|
1179
1206
|
self.figures.append(fig)
|
|
1180
1207
|
fig.plot(figure=figure, savefile=savefile)
|
|
@@ -1185,7 +1212,9 @@ class Posterior(object):
|
|
|
1185
1212
|
self, fignum=None, axes=None, quantile=None,
|
|
1186
1213
|
nx=None, ny=None,
|
|
1187
1214
|
savefile=None,
|
|
1215
|
+
fontsize=11, linewidth=1.5,
|
|
1188
1216
|
show_texts=None, show_estimates=None,
|
|
1217
|
+
alpha=0.6,
|
|
1189
1218
|
):
|
|
1190
1219
|
"""
|
|
1191
1220
|
Plot histogram of marginal posteriors.
|
|
@@ -1194,6 +1223,8 @@ class Posterior(object):
|
|
|
1194
1223
|
show_estimates = self.show_estimates
|
|
1195
1224
|
if show_texts is None:
|
|
1196
1225
|
show_texts = self.show_texts
|
|
1226
|
+
if quantile is None:
|
|
1227
|
+
quantile = self.quantile
|
|
1197
1228
|
|
|
1198
1229
|
fig = Marginal(
|
|
1199
1230
|
self,
|
|
@@ -1201,8 +1232,12 @@ class Posterior(object):
|
|
|
1201
1232
|
self.ranges, self.theme,
|
|
1202
1233
|
statistics=self.statistics,
|
|
1203
1234
|
nx=nx, ny=ny,
|
|
1235
|
+
quantile=quantile,
|
|
1236
|
+
fontsize=fontsize,
|
|
1237
|
+
linewidth=linewidth,
|
|
1204
1238
|
show_texts=show_texts,
|
|
1205
1239
|
show_estimates=show_estimates,
|
|
1240
|
+
alpha=alpha,
|
|
1206
1241
|
)
|
|
1207
1242
|
self.figures.append(fig)
|
|
1208
1243
|
fig.plot(savefile=savefile, fignum=fignum, axes=axes)
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
# Copyright (c) 2015-
|
|
1
|
+
# Copyright (c) 2015-2026 Patricio Cubillos and contributors.
|
|
2
2
|
# mc3 is open-source software under the MIT license (see LICENSE).
|
|
3
3
|
|
|
4
4
|
from .gelman import *
|
|
5
5
|
from .stats import *
|
|
6
6
|
from .time_averaging import *
|
|
7
|
+
from .dwt import *
|
|
7
8
|
from .prayer import *
|
|
8
9
|
|
|
9
10
|
__all__ = (
|
|
10
11
|
gelman.__all__
|
|
11
12
|
+ stats.__all__
|
|
12
13
|
+ time_averaging.__all__
|
|
14
|
+
+ dwt.__all__
|
|
13
15
|
+ prayer.__all__
|
|
14
16
|
)
|
|
15
17
|
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Copyright (c) 2015-2026 Patricio Cubillos and contributors.
|
|
2
|
+
# mc3 is open-source software under the MIT license (see LICENSE).
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
'daubechies4',
|
|
6
|
+
'dwt_daub4',
|
|
7
|
+
'dwt_chisq',
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def daubechies4(array, n, inverse):
|
|
14
|
+
"""
|
|
15
|
+
Applies the Daubechies-4 discrete wavelet transform (DWT)
|
|
16
|
+
or its inverse (transpose filter) depending on isign.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
a : np.ndarray
|
|
21
|
+
Input signal (1D array of length n).
|
|
22
|
+
Modified in place.
|
|
23
|
+
n: int
|
|
24
|
+
Hierarchy level of the transform.
|
|
25
|
+
inverse: bool
|
|
26
|
+
Calculate forward (False) or inverse (True) DWT
|
|
27
|
+
"""
|
|
28
|
+
C0 = 0.48296291314453410
|
|
29
|
+
C1 = 0.83651630373780772
|
|
30
|
+
C2 = 0.22414386804201339
|
|
31
|
+
C3 = -0.12940952255126034
|
|
32
|
+
|
|
33
|
+
if len(array) < 4:
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
dwt = np.zeros(n)
|
|
37
|
+
k = n >> 1 # n/2 using bit shift
|
|
38
|
+
|
|
39
|
+
if inverse:
|
|
40
|
+
dwt[0] = C2*array[k-1] + C1*array[n-1] + C0*array[0] + C3*array[k]
|
|
41
|
+
dwt[1] = C3*array[k-1] - C0*array[n-1] + C1*array[0] - C2*array[k]
|
|
42
|
+
j = 2
|
|
43
|
+
for i in range(0, k-1):
|
|
44
|
+
dwt[j] = C2*array[i] + C1*array[i+k] + C0*array[i+1] + C3*array[i+k+1]
|
|
45
|
+
dwt[j+1] = C3*array[i] - C0*array[i+k] + C1*array[i+1] - C2*array[i+k+1]
|
|
46
|
+
j += 2
|
|
47
|
+
else: # Forward transform
|
|
48
|
+
i = 0
|
|
49
|
+
for j in range(0, n-3, 2):
|
|
50
|
+
dwt[i] = C0*array[j] + C1*array[j+1] + C2*array[j+2] + C3*array[j+3]
|
|
51
|
+
dwt[i+k] = C3*array[j] - C2*array[j+1] + C1*array[j+2] - C0*array[j+3]
|
|
52
|
+
i += 1
|
|
53
|
+
# Wrap-around (circular convolution)
|
|
54
|
+
dwt[i] = C0*array[n-2] + C1*array[n-1] + C2*array[0] + C3*array[1]
|
|
55
|
+
dwt[i+k] = C3*array[n-2] - C2*array[n-1] + C1*array[0] - C0*array[1]
|
|
56
|
+
|
|
57
|
+
# Copy back into input array
|
|
58
|
+
array[0:n] = dwt
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def dwt_daub4(array, inverse=False):
|
|
62
|
+
"""
|
|
63
|
+
1D discrete wavelet transform using the Daubechies 4-parameter wavelet
|
|
64
|
+
Implements the pyramid algorithm replacing array by its DWT or inverse DWT
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
array: 1D float array
|
|
69
|
+
Input data array to which to apply the DWT (modified in place)
|
|
70
|
+
inverse: bool
|
|
71
|
+
Calculate forward (False) or inverse (True) DWT
|
|
72
|
+
|
|
73
|
+
Notes
|
|
74
|
+
-----
|
|
75
|
+
The input vector must have length 2**M with M an integer, otherwise
|
|
76
|
+
the output will zero-padded to the next size of the form 2**M.
|
|
77
|
+
|
|
78
|
+
Examples
|
|
79
|
+
--------
|
|
80
|
+
>>> import numpy as np
|
|
81
|
+
>>> import matplotlib.pyplot as plt
|
|
82
|
+
>>> import mc3.stats as ms
|
|
83
|
+
|
|
84
|
+
>>> # Calculate the inverse DWT for a unit vector:
|
|
85
|
+
>>> nx = 1000
|
|
86
|
+
>>> array = np.zeros(nx)
|
|
87
|
+
>>> array[10:20] = 1.0
|
|
88
|
+
>>> inverse = True
|
|
89
|
+
>>> idwt = ms.dwt_daub4(array, inverse=inverse)
|
|
90
|
+
>>> dwt_array = dawt(array, inverse=inverse)
|
|
91
|
+
|
|
92
|
+
>>> # Plot the inverse DWT
|
|
93
|
+
>>> fig = plt.figure(10)
|
|
94
|
+
>>> fig.set_size_inches(7,4)
|
|
95
|
+
>>> plt.clf()
|
|
96
|
+
>>> plt.subplots_adjust(0.1, 0.1, 0.99, 0.96)
|
|
97
|
+
>>> plt.plot(1-dwt_array/idwt, label='py DWT', color='k')
|
|
98
|
+
>>> plt.plot(0.1*array, label='signal', color='tomato')
|
|
99
|
+
>>> plt.plot(idwt, label='DWT', color='xkcd:blue')
|
|
100
|
+
>>> plt.plot(dwt_array, label='py DWT', color='limegreen', dashes=(8,3))
|
|
101
|
+
"""
|
|
102
|
+
size = len(array)
|
|
103
|
+
M = np.ceil(np.log2(size))
|
|
104
|
+
dwt_size = 2**int(M)
|
|
105
|
+
|
|
106
|
+
dwt_array = np.zeros(dwt_size)
|
|
107
|
+
dwt_array[0:size] = array
|
|
108
|
+
|
|
109
|
+
if size < 4:
|
|
110
|
+
return dwt_array
|
|
111
|
+
|
|
112
|
+
if inverse:
|
|
113
|
+
# Inverse transform: start from smallest hierarchy to largest
|
|
114
|
+
n = 4
|
|
115
|
+
while n <= dwt_size:
|
|
116
|
+
daubechies4(dwt_array, n, inverse)
|
|
117
|
+
n <<= 1
|
|
118
|
+
else:
|
|
119
|
+
# Forward transform: start from largest hierarchy to smallest
|
|
120
|
+
n = dwt_size
|
|
121
|
+
while n >= 4:
|
|
122
|
+
daubechies4(dwt_array, n, inverse)
|
|
123
|
+
n >>= 1
|
|
124
|
+
|
|
125
|
+
return dwt_array
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def dwt_chisq(model, data, params, priors=None, priorlow=None, priorup=None):
|
|
129
|
+
"""
|
|
130
|
+
Calculate -2*ln(likelihood) in a wavelet-base (a pseudo chi-squared)
|
|
131
|
+
based on Carter & Winn (2009), ApJ 704, 51.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
model: 1D ndarray
|
|
136
|
+
Model fit of data.
|
|
137
|
+
data: 1D ndarray
|
|
138
|
+
Data set array fitted by model.
|
|
139
|
+
params: 1D float ndarray
|
|
140
|
+
Model parameters (including the tree noise parameters: gamma,
|
|
141
|
+
sigma_r, sigma_w; which must be the last three elements in params).
|
|
142
|
+
priors: 1D ndarray
|
|
143
|
+
Parameter prior values.
|
|
144
|
+
priorlow: 1D ndarray
|
|
145
|
+
Left-sided prior standard deviation (param < prior).
|
|
146
|
+
A priorlow value of zero denotes a uniform prior.
|
|
147
|
+
priorup: 1D ndarray
|
|
148
|
+
Right-sided prior standard deviation (prior < param).
|
|
149
|
+
A priorup value of zero denotes a uniform prior.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
chisq: Float
|
|
154
|
+
Wavelet-based (pseudo) chi-squared.
|
|
155
|
+
|
|
156
|
+
Notes
|
|
157
|
+
-----
|
|
158
|
+
- If the residuals array size is not of the form 2**N, the routine
|
|
159
|
+
zero-pads the array until this condition is satisfied.
|
|
160
|
+
|
|
161
|
+
Examples
|
|
162
|
+
--------
|
|
163
|
+
>>> import mc3.stats as ms
|
|
164
|
+
>>> import numpy as np
|
|
165
|
+
>>> # Compute chi-squared for a given model fitting a data set:
|
|
166
|
+
>>> data = np.array([2.0, 0.0, 3.0, -2.0, -1.0, 2.0, 2.0, 0.0])
|
|
167
|
+
>>> model = np.ones(len(data))
|
|
168
|
+
>>> params = np.array([1.0, 0.1, 0.1])
|
|
169
|
+
>>> chisq = ms.dwt_chisq(model, data, params)
|
|
170
|
+
>>> print(chisq)
|
|
171
|
+
1693.22308882
|
|
172
|
+
|
|
173
|
+
>>> # Now, say this is a three-parameter model, with a Gaussian prior
|
|
174
|
+
>>> # on the last parameter:
|
|
175
|
+
>>> priors = np.array([1.0, 0.2, 0.3])
|
|
176
|
+
>>> plow = np.array([0.0, 0.0, 0.1])
|
|
177
|
+
>>> pup = np.array([0.0, 0.0, 0.1])
|
|
178
|
+
>>> chisq = ms.dwt_chisq(model, data, params, priors, plow, pup)
|
|
179
|
+
>>> print(chisq)
|
|
180
|
+
1697.2230888243134
|
|
181
|
+
"""
|
|
182
|
+
if len(params) < 3:
|
|
183
|
+
raise ValueError('Wavelet chisq should have at least three parameters')
|
|
184
|
+
|
|
185
|
+
# g-factor of the covariance of the wavelet coefficients:
|
|
186
|
+
# g(gamma=1) = 1.0 / (2*ln(2))
|
|
187
|
+
g = 0.72134752
|
|
188
|
+
|
|
189
|
+
size = len(data)
|
|
190
|
+
M = int(np.ceil(np.log2(size)))
|
|
191
|
+
|
|
192
|
+
# Expand (zero padding) to res to a size proportional to 2**M (zero padding)
|
|
193
|
+
residuals = np.zeros(2**M)
|
|
194
|
+
residuals[0:size] = data - model
|
|
195
|
+
dwt_residuals = dwt_daub4(residuals, inverse=False)
|
|
196
|
+
|
|
197
|
+
gamma, sigma_r, sigma_w = params[-3:]
|
|
198
|
+
# Equation (34) of CW2009, square of sigma_S
|
|
199
|
+
sigma_S = g * sigma_r**2.0 * 2.0**-gamma + sigma_w**2.0
|
|
200
|
+
# Second term in right-hand side of equation 32
|
|
201
|
+
chisq = (
|
|
202
|
+
(dwt_residuals[0]**2.0 + dwt_residuals[1]**2.0) / sigma_S +
|
|
203
|
+
2.0*np.log(2*np.pi*sigma_S)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Equation (33) of CW2009, sigma_W squared
|
|
207
|
+
for m in range(1, M): # Number of scales
|
|
208
|
+
sigma_W = sigma_r**2.0 * 2.0**(-gamma*m) + sigma_w**2.0
|
|
209
|
+
n = 2**m
|
|
210
|
+
res_sq = np.sum(dwt_residuals[n:2*n]**2.0)
|
|
211
|
+
chisq += res_sq/sigma_W + n*np.log(2*np.pi*sigma_W)
|
|
212
|
+
|
|
213
|
+
# Add priors contribution
|
|
214
|
+
if priors is None or priorlow is None or priorup is None:
|
|
215
|
+
return chisq
|
|
216
|
+
|
|
217
|
+
delta_priors = params - priors
|
|
218
|
+
for d_prior, e_low, e_up in zip(delta_priors, priorlow, priorup):
|
|
219
|
+
# No prior
|
|
220
|
+
if e_low<=0 or e_up<=0:
|
|
221
|
+
continue
|
|
222
|
+
# Gaussian prior
|
|
223
|
+
if d_prior > 0:
|
|
224
|
+
chisq += (d_prior/e_up)**2.0
|
|
225
|
+
else:
|
|
226
|
+
chisq += (d_prior/e_low)**2.0
|
|
227
|
+
|
|
228
|
+
return chisq
|
|
229
|
+
|