├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── COPYING
├── Dockerfile
├── README.md
├── XML
├── 4_time_samples_muinf.xml
├── 4_time_samples_muinf_fixed_alignment.xml
├── ALLtest.xml
├── BFTest.xml
├── BSSVS
│ ├── 4deme.xml
│ ├── 4deme_pole.xml
│ ├── 4deme_static.xml
│ ├── CVsampler.py
│ ├── CVwithPole.xml
│ └── pole_plots.R
├── EwingTest.xml
├── EwingTest2.xml
├── NSRtest1.xml
├── NSRtest2.xml
├── STXRtest.xml
├── STXtest.xml
├── Sanity.xml
├── TWBRtest.xml
├── TWBtest.xml
├── analysis
│ ├── CWB_SC_3taxa.pdf
│ ├── SC_3taxa.pdf
│ ├── SC_3taxa_combined.pdf
│ ├── fit_height_distribs.R
│ ├── fits0.1.pdf
│ ├── fits0.2.pdf
│ ├── plot_3taxa.R
│ └── plot_CWB_3taxa.R
├── badness_eradication
│ ├── 2deme_0.5samples.xml
│ ├── conditionedPathGen.R
│ ├── countSampling.R
│ ├── hybrid.xml
│ ├── plot_countProb.R
│ ├── simulated_alignment.xml
│ └── true_tree.nexus
├── figure_StructuredCoalescentColouredTree.xml
├── large_mrate_testing
│ ├── large_mrate_inference.xml
│ ├── large_mrate_inference_fixed_alignment.xml
│ ├── large_mrate_test.template
│ ├── largem_results.pdf
│ ├── plot_results.R
│ ├── runsamps.sh
│ └── runsims.sh
└── simulated_data
│ ├── alignmentConverter
│ ├── full_inference.xml
│ ├── simulated_alignment.xml
│ └── true_tree.nexus
├── action.yml
├── build.xml
├── doc
├── .gitignore
└── operator_notes
│ ├── SubtreeSlide.tex
│ └── WilsonBaldingRandom.tex
├── examples
├── h3n2.fna
├── h3n2_2deme.fna
└── structuredCoalescent.xml
├── fxtemplates
├── MTTClockModels.xml
└── MultiTypeTree.xml
├── lib
├── LICENSE.guava
├── LICENSE.jblas
├── guava-15.0.jar
└── jblas-1.2.5.jar
├── src
└── multitypetree
│ ├── app
│ └── beauti
│ │ ├── InitMigrationModelConnector.java
│ │ ├── MigrationModelInputEditor.java
│ │ ├── MigrationModelInputEditorFX.java
│ │ └── TypeTraitSetInputEditor.java
│ ├── distributions
│ ├── ExcludablePrior.java
│ ├── MRCATypePrior.java
│ ├── MultiTypeTreeDistribution.java
│ ├── PriorWithPole.java
│ ├── StructuredCoalescentTreeDensity.java
│ ├── StructuredCoalescentUntypedTreeDensity.java
│ └── TypeChangeTimeCondition.java
│ ├── evolution
│ └── tree
│ │ ├── FlatMultiTypeTree.java
│ │ ├── MigrationModel.java
│ │ ├── MultiTypeNode.java
│ │ ├── MultiTypeTree.java
│ │ ├── MultiTypeTreeFromFlatTree.java
│ │ ├── MultiTypeTreeFromNewick.java
│ │ ├── MultiTypeTreeFromUntypedNewick.java
│ │ ├── RandomMultiTypeTree.java
│ │ ├── SCMigrationModel.java
│ │ ├── StructuredCoalescentMultiTypeTree.java
│ │ ├── StructuredCoalescentUntypedTree.java
│ │ └── TypeSet.java
│ ├── operators
│ ├── BeerliFelsenstein.java
│ ├── MultiTypeTreeOperator.java
│ ├── MultiTypeTreeScale.java
│ ├── MultiTypeUniform.java
│ ├── NodeRetype.java
│ ├── NodeRetypeRandom.java
│ ├── NodeShiftRetype.java
│ ├── NodeShiftRetypeRandom.java
│ ├── RandomRetypeOperator.java
│ ├── SpecialTypeBirthDeath.java
│ ├── TypeBirthDeath.java
│ ├── TypeMergeSplit.java
│ ├── TypeMergeSplitExtended.java
│ ├── TypePairBirthDeath.java
│ ├── TypedSubtreeExchange.java
│ ├── TypedSubtreeExchangeEasy.java
│ ├── TypedSubtreeExchangeRandom.java
│ ├── TypedWilsonBalding.java
│ ├── TypedWilsonBaldingEasy.java
│ ├── TypedWilsonBaldingRandom.java
│ ├── UniformizationRetypeOperator.java
│ └── ZeroJump.java
│ └── util
│ ├── MAPTreeLogger.java
│ ├── MigrationModelLogger.java
│ ├── MultiTypeTreeStatLogger.java
│ ├── NodeTypeCounts.java
│ ├── TreeLengthLogger.java
│ ├── TreeRootTypeLogger.java
│ ├── TypeChangeCounts.java
│ ├── TypeLengths.java
│ ├── TypedNodeTreeLogger.java
│ └── UtilMethods.java
├── test
└── multitypetree
│ ├── coalescent
│ └── SCLikelihoodTest.java
│ └── operators
│ ├── Ewing_Test.java
│ ├── NSR_Test.java
│ ├── STXR_NRR_MTU_TS_Test.java
│ ├── STX_NR_MTU_TS_Test.java
│ ├── TWBR_TS_Test.java
│ └── TWB_TS_Test.java
└── version.xml
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Unit/integration tests
2 | on:
3 | push:
4 | branches: [ master ]
5 | pull_request:
6 | branches: [ master ]
7 |
8 | # Allows you to run this workflow manually from the Actions tab
9 | workflow_dispatch:
10 |
11 | jobs:
12 | test:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v2
16 | - uses: tgvaughan/MultiTypeTree@master
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build directories
2 | /dist
3 | /build
4 | /build-lib
5 | /out
6 |
7 | # netbeans cruft
8 | /nbbuild.xml
9 | /manifest.mf
10 | /nbproject
11 |
12 | # intellij cruft
13 | /.idea
14 | /MultiTypeTree.iml
15 | /META-INF
16 |
17 | # Ignore BEAST logfiles
18 | *.log
19 | *.trees
20 | *.state
21 |
22 | # Other cruft:
23 | .localrc
24 | .localrcbye
25 | /examples/h3n2
26 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Dockerfile to build container for unit testing
2 |
3 | FROM debian:stable
4 |
5 | RUN apt-get update
6 | RUN apt-get install -y openjdk-17-jdk openjfx
7 | RUN apt-get install -y ant
8 | RUN apt-get install -y jblas
9 |
10 | WORKDIR /root
11 |
12 | ADD . ./
13 |
14 | RUN rm lib/jblas-*.jar
15 | RUN ln -s /usr/share/java/jblas.jar lib/jblas.jar
16 |
17 | ENTRYPOINT JAVA_FX_HOME=/usr/share/java/ ant test
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MultiTypeTree
2 | =============
3 |
4 | This is a BEAST 2 package which allows for the inference of multi-type
5 | or structured phylogenetic trees. It includes a full set of proposal
6 | operators and currently the structured coalescent model, allowing
7 | migration rates and sub-population sizes to be inferred from
8 | serially-sampled sequence data. The multi-type trees and the
9 | operators contained in this package can also be used as the basis for
10 | structured population inference under other models.
11 |
12 | For further information, please refer to the MultiTypeTree [web
13 | page](http://tgvaughan.github.io/MultiTypeTree).
14 |
15 | [](https://github.com/tgvaughan/MultiTypeTree/actions?query=workflow%3A%22Unit%2Fintegration+tests%22)
16 |
17 | License
18 | -------
19 |
20 | This software is free (as in freedom). With the exception of the
21 | libraries on which it depends, it is made available under the terms of
22 | the GNU General Public Licence version 3, which is contained in this
23 | directory in the file named COPYING.
24 |
25 | The following libraries are bundled with MultiTypeTree:
26 |
27 | * Google Guava (http://code.google.com/p/guava-libraries/)
28 | * jblas (http://mikiobraun.github.io/jblas/)
29 |
30 | That software is distributed under the licences provided in the
31 | LICENCE.* files included in this archive.
32 |
33 | Work on this project is made possible by generous funding from the
34 | [Allan Wilson Centre for Molecular Ecology and
35 | Evolution](http://www.allanwilsoncentre.ac.nz/).
36 |
--------------------------------------------------------------------------------
/XML/ALLtest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
34 |
35 |
37 |
38 |
42 |
43 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/XML/BFTest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/XML/BSSVS/CVsampler.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from scipy import *
4 | import scipy.stats as stats
5 | from matplotlib import pylab
6 |
7 | seterr(divide='raise')
8 |
9 | class State:
10 | x = None
11 | xStored = None
12 |
13 | def __init__(self, x0):
14 | self.x = x0
15 |
16 | def store(self):
17 | self.xStored = self.x
18 |
19 | def restore(self):
20 | self.x = self.xStored
21 |
22 | def proposeJump (state):
23 | logHR = 0
24 |
25 | if state.x>0:
26 | logHR = log(stats.beta.pdf(state.x,1,5))
27 | state.x = 0
28 | else:
29 | state.x = stats.beta.rvs(1,5)
30 | logHR = -log(stats.beta.pdf(state.x,1,5))
31 |
32 | return logHR
33 |
34 | def proposeScale (state):
35 | # if state.x>0:
36 | fmin = 0.9
37 | fmax = 1/0.9
38 | f = stats.uniform.rvs(fmin,(fmax-fmin))
39 |
40 | state.x *= f
41 |
42 | return -log(f)
43 |
44 | # else:
45 | # return -float('inf')
46 |
47 |
48 | def targetDensity (state):
49 |
50 | p0 = 0.05
51 |
52 | if state.x>0:
53 | if state.x<1:
54 | return log((1-p0)*stats.beta.pdf(state.x,2,2))
55 | else:
56 | return -float('inf')
57 | else:
58 | return log(p0)
59 |
60 |
61 | def MCMC ():
62 |
63 | burninFrac = 0.2
64 | maxiter = 100000
65 | sampPeriod = 10
66 |
67 | chain = []
68 |
69 | state = State(0.5)
70 |
71 | for i in range(maxiter):
72 |
73 | state.store()
74 |
75 | logAlpha = -targetDensity(state)
76 |
77 | logHR = 0.0
78 | if stats.uniform.rvs(0,1)<0.5:
79 | logHR = proposeJump(state)
80 | else:
81 | logHR = proposeScale(state)
82 |
83 | logAlpha += targetDensity(state) + logHR
84 |
85 | if stats.uniform.rvs(0,1)>exp(logAlpha):
86 | state.restore()
87 |
88 | if i>maxiter*burninFrac and i%sampPeriod==0:
89 | chain.append(state.x)
90 |
91 | return chain
92 |
93 |
94 | if __name__ == '__main__':
95 |
96 | chain = MCMC()
97 |
98 | zeroFrac = sum([float(x==0) for x in chain])/len(chain)
99 | print "Zero fraction = {}".format(zeroFrac)
100 |
101 | pylab.hist(chain, bins=50)
102 | pylab.show()
103 |
--------------------------------------------------------------------------------
/XML/BSSVS/CVwithPole.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/XML/BSSVS/pole_plots.R:
--------------------------------------------------------------------------------
1 | df <- read.table('4deme_pole.log', header=T)
2 |
3 | burninfrac = 0.1
4 | indices <- round(burninfrac*length(df$Sample)):length(df$Sample)
5 |
6 | nparams <- (df$migModel.rateMatrixBackward_0_1>0) +
7 | (df$migModel.rateMatrixBackward_0_2>0) +
8 | (df$migModel.rateMatrixBackward_0_3>0) +
9 | (df$migModel.rateMatrixBackward_1_0>0) +
10 | (df$migModel.rateMatrixBackward_1_2>0) +
11 | (df$migModel.rateMatrixBackward_1_3>0) +
12 | (df$migModel.rateMatrixBackward_2_0>0) +
13 | (df$migModel.rateMatrixBackward_2_1>0) +
14 | (df$migModel.rateMatrixBackward_2_3>0) +
15 | (df$migModel.rateMatrixBackward_3_0>0) +
16 | (df$migModel.rateMatrixBackward_3_1>0) +
17 | (df$migModel.rateMatrixBackward_3_2>0)
18 |
--------------------------------------------------------------------------------
/XML/EwingTest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
34 |
36 |
37 |
38 |
39 |
42 |
44 |
45 |
48 |
49 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/XML/EwingTest2.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
34 |
37 |
38 |
39 |
40 |
43 |
44 |
46 |
47 |
49 |
50 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/XML/NSRtest1.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 | (1[state='1']:1,2[state='0']:1)[state='0']:0;
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/XML/NSRtest2.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 | ((1[state='0']:1,2[state='0']:1)[state='0']:1,3[state='0']:2)[state='0']:0;
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/XML/STXRtest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 | ((1[state='0']:1,2[state='0']:1)[state='0']:1,3[state='0']:2)[state='0']:0;
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
35 |
36 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/XML/STXtest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
34 |
35 |
37 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/XML/Sanity.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
39 |
40 |
43 |
44 |
47 |
48 |
51 |
52 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/XML/TWBRtest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 | ((1[deme='0']:1,2[deme='0']:1)[deme='0']:1,3[deme='0']:2)[deme='0']:0;
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
60 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/XML/TWBtest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 | ((1[deme='0']:1,2[deme='0']:1)[deme='0']:1,3[deme='0']:2)[deme='0']:0;
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
60 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/XML/analysis/CWB_SC_3taxa.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/XML/analysis/CWB_SC_3taxa.pdf
--------------------------------------------------------------------------------
/XML/analysis/SC_3taxa.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/XML/analysis/SC_3taxa.pdf
--------------------------------------------------------------------------------
/XML/analysis/SC_3taxa_combined.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/XML/analysis/SC_3taxa_combined.pdf
--------------------------------------------------------------------------------
/XML/analysis/fit_height_distribs.R:
--------------------------------------------------------------------------------
1 | # Fit gamma distributions to densities of sampled tree
2 | # heights and compare with exact results for summary statistics
3 |
4 | # Clear workspace
5 | rm(list=ls())
6 |
7 | require(MASS)
8 |
9 | # Data set to use:
10 | mu=0.1
11 |
12 | muStr = format(mu, digits=1)
13 |
14 | # Fraction of chain to discard:
15 | burninFrac <- 0.2
16 |
17 | # Load results of MCMC runs:
18 | dfSame <- read.table(paste('SC_same',muStr,'.log',sep=''), header=T)
19 | dfDiff <- read.table(paste('SC_different',muStr,'.log',sep=''), header=T)
20 |
21 | burnin <- floor(length(dfSame$tree.height)*burninFrac)
22 | datSame <- dfSame$tree.height[seq(1,length(dfSame$tree.height))>burnin]
23 | burnin <- floor(length(dfDiff$tree.height)*burninFrac)
24 | datDiff <- dfDiff$tree.height[seq(1,length(dfDiff$tree.height))>burnin]
25 |
26 | sameMean <- mean(datSame)
27 | sameVar <- var(datSame)
28 | diffMean <- mean(datDiff)
29 | diffVar <- var(datDiff)
30 |
31 | # Set up plot:
32 | pdf(paste('fits',muStr,'.pdf',sep=''), width=7, height=5)
33 |
34 | histSame <- hist(datSame, breaks=500, plot=F)
35 | plot(histSame$mids, histSame$density, 'l', lwd=2, col='blue',
36 | xlab='Tree height',
37 | ylab='Density',
38 | main=substitute(paste("Tuning parameter ",mu==muval),list(muval=mu)))
39 |
40 | fitSame <- fitdistr(datSame, "gamma")
41 | lines(histSame$mids, dgamma(histSame$mids, shape=fitSame$estimate[[1]],
42 | rate=fitSame$estimate[[2]]), lwd=2, lty=2, col='blue')
43 |
44 | fitSameMean <- fitSame$estimate[[1]]/fitSame$estimate[[2]]
45 | fitSameVar <- fitSame$estimate[[1]]/fitSame$estimate[[2]]^2
46 |
47 | histDiff <- hist(datDiff, breaks=500, plot=F)
48 | lines(histDiff$mids, histDiff$density, lwd=2, col='red')
49 |
50 | fitDiff <- fitdistr(datDiff, "gamma")
51 | lines(histDiff$mids, dgamma(histDiff$mids, shape=fitDiff$estimate[[1]],
52 | rate=fitDiff$estimate[[2]]), lwd=2, lty=2, col='red')
53 |
54 | fitDiffMean <- fitDiff$estimate[[1]]/fitDiff$estimate[[2]]
55 | fitDiffVar <- fitDiff$estimate[[1]]/fitDiff$estimate[[2]]^2
56 |
57 | legend('topright', inset=.05,
58 | c(paste('Same deme: mean=', format(sameMean, digits=4),
59 | ' var=',format(sameVar, digits=4), sep=''),
60 | paste('Different demes: mean=', format(diffMean, digits=4),
61 | ' var=', format(diffVar, digits=4), sep=''),
62 | 'Fitted gamma distributions'),
63 | lty=c(1,1,2), col=c('blue','red','black'), lwd=2)
64 |
65 | dev.off()
66 |
--------------------------------------------------------------------------------
/XML/analysis/fits0.1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/XML/analysis/fits0.1.pdf
--------------------------------------------------------------------------------
/XML/analysis/fits0.2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/XML/analysis/fits0.2.pdf
--------------------------------------------------------------------------------
/XML/analysis/plot_3taxa.R:
--------------------------------------------------------------------------------
1 | # Analysis of 3 taxon sampling results
2 |
3 | # Clear workspace:
4 | rm(list=ls())
5 |
6 | # Load data:
7 | dfSimSame <- read.table('SC_3taxa_same_sim.txt', header=T)
8 | dfSame <- read.table('SC_3taxa_same.log', header=T)
9 | dfSimDiff <- read.table('SC_3taxa_diff_sim.txt', header=T)
10 | dfDiff <- read.table('SC_3taxa_diff.log', header=T)
11 | dfSameComb <- read.table('SC_3taxa_same_combined.log', header=T)
12 | dfDiffComb <- read.table('SC_3taxa_diff_combined.log', header=T)
13 |
14 | # Calculate means and variances
15 | burninFrac <- 0.05
16 |
17 | noburnin <- function(x, f) {
18 | return(x[seq(1,length(x))>(f*length(x))])
19 | }
20 |
21 | datSimSame <- noburnin(dfSimSame$h, burninFrac)
22 | meanSimSame <- mean(datSimSame)
23 | varSimSame <- var(datSimSame)
24 | semSimSame <- sqrt(varSimSame/length(datSimSame))
25 |
26 | datSame <- noburnin(dfSame$tree.height, burninFrac)
27 | meanSame <- mean(datSame)
28 | varSame <- var(datSame)
29 | semSame <- sqrt(varSame/length(datSame))
30 |
31 | datSimDiff <- noburnin(dfSimDiff$h, burninFrac)
32 | meanSimDiff <- mean(datSimDiff)
33 | varSimDiff <- var(datSimDiff)
34 | semSimDiff <- sqrt(varSimDiff/length(datSimDiff))
35 |
36 | datDiff <- noburnin(dfDiff$tree.height, burninFrac)
37 | meanDiff <- mean(datDiff)
38 | varDiff <- var(datDiff)
39 | semDiff <- sqrt(varDiff/length(datDiff))
40 |
41 | # Calculate densities:
42 | hSimSame <- hist(datSimSame, breaks=200, plot=F)
43 | hSame <- hist(datSame, breaks=200, plot=F)
44 | hSimDiff <- hist(datSimDiff, breaks=200, plot=F)
45 | hDiff <- hist(datDiff, breaks=200, plot=F)
46 |
47 |
48 | # Plot figure
49 | pdf('SC_3taxa.pdf', onefile=F, width=7, height=5)
50 | plot(hSame$mids, hSame$density, 'l', lwd=1, col='blue',
51 | xlab='Tree height',
52 | ylab='Rel. frequency',
53 | main='Coloured WB operator on 3 taxon trees under SC')
54 | lines(hSimSame$mids, hSimSame$density, lwd=2, lty=2, col='blue')
55 | lines(hDiff$mids, hDiff$density, 'l', lwd=1, col='red')
56 | lines(hSimDiff$mids, hSimDiff$density, lwd=2, lty=2, col='red')
57 |
58 | # Add descriptive legend
59 | legend('topright', inset=.05,
60 | c(paste('Same (MCMC): mean=', format(meanSame, digits=4),
61 | '+/-', format(semSame, digits=2),
62 | ', var=', format(varSame, digits=4),
63 | sep=''),
64 | paste('Same (sim): mean=', format(meanSimSame, digits=4),
65 | '+/-', format(semSimSame, digits=2),
66 | ', var=', format(varSimSame, digits=4),
67 | sep=''),
68 | paste('Diff (MCMC): mean=', format(meanDiff, digits=4),
69 | '+/-', format(semDiff, digits=2),
70 | ', var=', format(varDiff, digits=4),
71 | sep=''),
72 | paste('Diff (sim): mean=', format(meanSimDiff, digits=4),
73 | '+/-', format(semSimDiff, digits=2),
74 | ', var=', format(varSimDiff, digits=4),
75 | sep='')),
76 | lty=c(1,2,1,2),
77 | lwd=c(1,2,1,2),
78 | col=c('blue','blue','red','red'))
79 |
80 | # Close figure:
81 | dev.off()
82 |
83 | # Process combined operator results:
84 | datSameComb <- noburnin(dfSameComb$tree.height, burninFrac)
85 | meanSameComb <- mean(datSameComb)
86 | varSameComb <- var(datSameComb)
87 | semSameComb <- sqrt(varSameComb/length(datSameComb))
88 | datDiffComb <- noburnin(dfDiffComb$tree.height, burninFrac)
89 | meanDiffComb <- mean(datDiffComb)
90 | varDiffComb <- var(datDiffComb)
91 | semDiffComb <- sqrt(varDiffComb/length(datDiffComb))
92 |
93 | hSameComb <- hist(datSameComb, breaks=200, plot=F)
94 | hDiffComb <- hist(datDiffComb, breaks=200, plot=F)
95 |
96 | # Plot combined operator results:
97 | pdf('SC_3taxa_combined.pdf', onefile=F, width=7, height=5)
98 | plot(hSameComb$mids, hSameComb$density, 'l', lwd=1, col='blue',
99 | xlab='Tree height',
100 | ylab='Rel. frequency',
101 | main='CWBR and tree scale operators on 3 taxon trees under SC')
102 | lines(hSimSame$mids, hSimSame$density, lwd=2, lty=2, col='blue')
103 | lines(hDiffComb$mids, hDiffComb$density, 'l', lwd=1, col='red')
104 | lines(hSimDiff$mids, hSimDiff$density, lwd=2, lty=2, col='red')
105 |
106 | # Add descriptive legend
107 | legend('topright', inset=.05,
108 | c(paste('Same (MCMC): mean=', format(meanSameComb, digits=4),
109 | '+/-', format(semSameComb, digits=2),
110 | ', var=', format(varSameComb, digits=4),
111 | sep=''),
112 | paste('Same (sim): mean=', format(meanSimSame, digits=4),
113 | '+/-', format(semSimSame, digits=2),
114 | ', var=', format(varSimSame, digits=4),
115 | sep=''),
116 | paste('Diff (MCMC): mean=', format(meanDiffComb, digits=4),
117 | '+/-', format(semDiffComb, digits=2),
118 | ', var=', format(varDiffComb, digits=4),
119 | sep=''),
120 | paste('Diff (sim): mean=', format(meanSimDiff, digits=4),
121 | '+/-', format(semSimDiff, digits=2),
122 | ', var=', format(varSimDiff, digits=4),
123 | sep='')),
124 | lty=c(1,2,1,2),
125 | lwd=c(1,2,1,2),
126 | col=c('blue','blue','red','red'))
127 |
128 | # Close figure:
129 | dev.off()
130 |
--------------------------------------------------------------------------------
/XML/analysis/plot_CWB_3taxa.R:
--------------------------------------------------------------------------------
1 | # Analysis of 3 taxon sampling results
2 |
3 | # Clear workspace:
4 | rm(list=ls())
5 |
6 | # Load data:
7 | dfSimSame <- read.table('SC_3taxa_same_sim.txt', header=T)
8 | dfSame <- read.table('CWB_SC_3taxa_same.log', header=T)
9 | dfSimDiff <- read.table('SC_3taxa_diff_sim.txt', header=T)
10 | dfDiff <- read.table('CWB_SC_3taxa_diff.log', header=T)
11 |
12 | # Calculate means and variances
13 | burninFrac <- 0.05
14 |
15 | noburnin <- function(x, f) {
16 | return(x[seq(1,length(x))>(f*length(x))])
17 | }
18 |
19 | datSimSame <- noburnin(dfSimSame$h, burninFrac)
20 | meanSimSame <- mean(datSimSame)
21 | varSimSame <- var(datSimSame)
22 | semSimSame <- sqrt(varSimSame/length(datSimSame))
23 |
24 | datSame <- noburnin(dfSame$tree.height, burninFrac)
25 | meanSame <- mean(datSame)
26 | varSame <- var(datSame)
27 | semSame <- sqrt(varSame/length(datSame))
28 |
29 | datSimDiff <- noburnin(dfSimDiff$h, burninFrac)
30 | meanSimDiff <- mean(datSimDiff)
31 | varSimDiff <- var(datSimDiff)
32 | semSimDiff <- sqrt(varSimDiff/length(datSimDiff))
33 |
34 | datDiff <- noburnin(dfDiff$tree.height, burninFrac)
35 | meanDiff <- mean(datDiff)
36 | varDiff <- var(datDiff)
37 | semDiff <- sqrt(varDiff/length(datDiff))
38 |
39 | # Calculate densities:
40 | hSimSame <- hist(datSimSame, breaks=200, plot=F)
41 | hSame <- hist(datSame, breaks=200, plot=F)
42 | hSimDiff <- hist(datSimDiff, breaks=200, plot=F)
43 | hDiff <- hist(datDiff, breaks=200, plot=F)
44 |
45 |
46 | # Plot figure
47 | pdf('CWB_SC_3taxa.pdf', onefile=F, width=7, height=5)
48 | plot(hSame$mids, hSame$density, 'l', lwd=1, col='blue',
49 | xlab='Tree height',
50 | ylab='Rel. frequency',
51 | main='Full CWB operator on 3 taxon trees under SC')
52 | lines(hSimSame$mids, hSimSame$density, lwd=2, lty=2, col='blue')
53 | lines(hDiff$mids, hDiff$density, 'l', lwd=1, col='red')
54 | lines(hSimDiff$mids, hSimDiff$density, lwd=2, lty=2, col='red')
55 |
56 | # Add descriptive legend
57 | legend('topright', inset=.05,
58 | c(paste('Same (MCMC): mean=', format(meanSame, digits=4),
59 | '+/-', format(semSame, digits=2),
60 | ', var=', format(varSame, digits=4),
61 | sep=''),
62 | paste('Same (sim): mean=', format(meanSimSame, digits=4),
63 | '+/-', format(semSimSame, digits=2),
64 | ', var=', format(varSimSame, digits=4),
65 | sep=''),
66 | paste('Diff (MCMC): mean=', format(meanDiff, digits=4),
67 | '+/-', format(semDiff, digits=2),
68 | ', var=', format(varDiff, digits=4),
69 | sep=''),
70 | paste('Diff (sim): mean=', format(meanSimDiff, digits=4),
71 | '+/-', format(semSimDiff, digits=2),
72 | ', var=', format(varSimDiff, digits=4),
73 | sep='')),
74 | lty=c(1,2,1,2),
75 | lwd=c(1,2,1,2),
76 | col=c('blue','blue','red','red'))
77 |
78 | # Close figure:
79 | dev.off()
80 |
--------------------------------------------------------------------------------
/XML/badness_eradication/conditionedPathGen.R:
--------------------------------------------------------------------------------
1 | # Conditioned CTMC path generation
2 |
3 | drawPath <- function (startType, m, L) {
4 |
5 | times <- c()
6 | types <- c()
7 |
8 | t <- 0
9 | d <- startType
10 | while (TRUE) {
11 |
12 | t <- t + rexp(1,-Q[d,d])
13 |
14 | destTypes <- which(Q[d,]>=0)
15 | d <- sample(destTypes, 1, prob=Q[d,destTypes])
16 |
17 | if (t>L) {
18 | break
19 | }
20 |
21 | times <- append(times,t)
22 | types <- append(types,d)
23 | }
24 |
25 | res <- list()
26 | res$times <- times
27 | res$types <- types
28 |
29 | return (res)
30 |
31 | }
32 |
33 | drawConditionedPath <- function (startType, endType, m, L) {
34 |
35 | while (TRUE) {
36 | res <- drawPath(startType, m, L)
37 | if (length(res$types)>0) {
38 | if (res$types[length(res$types)]==endType)
39 | return (res)
40 | } else {
41 | if (startType == endType)
42 | return (res)
43 | }
44 | }
45 |
46 | }
47 |
48 | generateEnsemble <- function (N, startType, endType, m, L) {
49 |
50 | totalCounts <- c()
51 | counts <- list()
52 |
53 | for (i in 1:N) {
54 | path <- drawConditionedPath(startType, endType, m, L)
55 | totalCounts <- append(totalCounts, length(path$times))
56 | if (i == 1) {
57 | for (c in 1:dim(m)[1])
58 | counts[[c]] <- sum(path$types==c)
59 | } else {
60 | for (c in 1:dim(m)[1])
61 | counts[[c]] <- append(counts[[c]], sum(path$types==c))
62 | }
63 | }
64 |
65 | res <- list()
66 | res$totalCounts <- totalCounts
67 | res$counts <- counts
68 |
69 | return (res)
70 |
71 | }
72 |
73 | # Four-colour path generation
74 | Q = matrix(
75 | data=c(
76 | -0.25, 0.20, 0.02, 0.03,
77 | 0.04, -0.15, 0.05, 0.06,
78 | 0.07, 0.08, -0.24, 0.09,
79 | 0.10, 0.11, 0.12, -0.33
80 | ),
81 | nrow=4, ncol=4, byrow=T)
82 |
83 | ensemble <- generateEnsemble(10000, 4, 2, Q, 200)
84 |
--------------------------------------------------------------------------------
/XML/badness_eradication/countSampling.R:
--------------------------------------------------------------------------------
1 | require(expm)
2 |
3 | # Set up matrices
4 | Q <- matrix(data=c(-208.516676, 208.516676, 0.002952, -0.002952),
5 | nrow=2, ncol=2, byrow=T)
6 | rho <- max(-diag(Q))
7 | R <- Q/rho + diag(2)
8 |
9 | lambda <- 1.008736926575113
10 | mu <- 208.5166757820231
11 | a <- 0
12 | b <- 0
13 |
14 | N <- 2
15 |
16 | # Slow but correct count sampling function:
17 | sampleCount <- function(sampleSize) {
18 |
19 | res <- rep(0,sampleSize)
20 | for (i in 1:sampleSize) {
21 | cat(paste("Sample",i,"\n"))
22 | repeat {
23 | n <- rpois(1, mu*lambda)
24 | P_b_given_na <- (R %^% n)[a+1, b+1]
25 | if (runif(1)N)
58 | break;
59 | }
60 | }
61 |
62 | res[i] <- n
63 | }
64 |
65 | return (res)
66 | }
67 |
--------------------------------------------------------------------------------
/XML/badness_eradication/plot_countProb.R:
--------------------------------------------------------------------------------
1 | require(expm)
2 |
3 | M <- matrix(data=c(0,0,0.05,0.05,
4 | 0.05,0,0.05,0,
5 | 0.05,0.05,0,0,
6 | 0,0,0,0), nrow=4, byrow=T)
7 |
8 | Q <- M - diag(rowSums(M))
9 | rho <- max(-diag(Q))
10 | R <- Q/rho + diag(4)
11 |
12 | a <- 2
13 | b <- 1
14 | L <- 0.04879582996085663
15 |
16 | muL <- rho*L
17 | Pba <- expm(Q*L)[a+1,b+1]
18 |
19 | n <- 0:200
20 |
21 | getLogP <- function(x) {
22 | logP <- (R %^% x)[a+1,b+1] + x*log(muL) - lgamma(x+1) - muL - Pba
23 | return(exp(logP))
24 | }
25 | probs <- lapply(n, getLogP)
26 |
--------------------------------------------------------------------------------
/XML/figure_StructuredCoalescentColouredTree.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
7 |
9 |
10 |
11 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
32 |
35 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/XML/large_mrate_testing/large_mrate_test.template:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
36 |
37 |
40 |
41 |
44 |
45 |
48 |
49 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/XML/large_mrate_testing/largem_results.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/XML/large_mrate_testing/largem_results.pdf
--------------------------------------------------------------------------------
/XML/large_mrate_testing/plot_results.R:
--------------------------------------------------------------------------------
1 | dfsims <- list()
2 | dfsamps <- list()
3 |
4 | mvals <- c(0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64)
5 |
6 | simHeightMeans <- rep(0,length(mvals))
7 | simHeightVars <- rep(0,length(mvals))
8 | simCountMeans <- rep(0,length(mvals))
9 | simCountVars <- rep(0,length(mvals))
10 |
11 | sampHeightMeans <- rep(0,length(mvals))
12 | sampHeightVars <- rep(0,length(mvals))
13 | sampCountMeans <- rep(0,length(mvals))
14 | sampCountVars <- rep(0,length(mvals))
15 |
16 |
17 | for (i in seq(1,length(mvals))) {
18 | m <- mvals[i]
19 | simfname <- paste('heights',m,'.txt', sep='')
20 | sampfname <- paste('large_mrate_test_',m,'.log', sep='')
21 |
22 | dfsim <- read.table(simfname, header=T)
23 | simHeightMeans[i] <- mean(dfsim$h)
24 | simHeightVars[i] <- var(dfsim$h)
25 | simCountMeans[i] <- mean(dfsim$c)
26 | simCountVars[i] <- var(dfsim$c)
27 |
28 | dfsamp <- read.table(sampfname, header=T)
29 | sampHeightMeans[i] <- mean(dfsamp$tree.height)
30 | sampHeightVars[i] <- var(dfsamp$tree.height)
31 | sampCountMeans[i] <- mean(dfsamp$tree.count)
32 | sampCountVars[i] <- var(dfsamp$tree.count)
33 | }
34 |
35 |
36 | # Plot figure
37 |
38 | pdf('largem_results.pdf', onefile=F, width=7, height=5)
39 | par(mfrow=c(2,2))
40 | par(mgp=c(1.5,0.5,0))
41 | par(mar=c(3,3,1.5,0.5))
42 |
43 | plot(mvals, simHeightMeans, 'o', col='red', xlab='m', ylab='tree height',
44 | main='tree height means', log='x')
45 | lines(mvals, sampHeightMeans, 'o', col='blue')
46 |
47 | plot(mvals, simCountMeans, 'o', col='red', xlab='m', ylab='migration count',
48 | main='migration count means', log='xy')
49 | lines(mvals, sampCountMeans, 'o', col='blue')
50 |
51 | plot(mvals, sqrt(simHeightVars), 'o', col='red', xlab='m', ylab='tree height',
52 | main='tree height std. dev.', log='x')
53 | lines(mvals, sqrt(sampHeightVars), 'o', col='blue')
54 |
55 | plot(mvals, sqrt(simCountVars), 'o', col='red', xlab='m', ylab='migration count',
56 | main='migration count std. dev.', log='xy')
57 | lines(mvals, sqrt(sampCountVars), 'o', col='blue')
58 |
59 | dev.off()
60 |
--------------------------------------------------------------------------------
/XML/large_mrate_testing/runsamps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | for m in 0.125 0.25 0.5 1 2 4 8 16 32 64; do
4 | sed 's/MRATE/'$m'/g' < large_mrate_test.template >large_mrate_test_$m.xml
5 | beast large_mrate_test_$m.xml
6 | done
7 |
--------------------------------------------------------------------------------
/XML/large_mrate_testing/runsims.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | for m in 0.125 0.25 0.5 1 2 4 8 16 32 64; do
4 | beast -main beast.evolution.tree.coalescent.StructuredCoalescentMultiTypeTree $m
5 | mv heights.txt heights$m.txt
6 | done
--------------------------------------------------------------------------------
/XML/simulated_data/alignmentConverter:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from sys import argv, exit, stdout
4 | from argparse import ArgumentParser
5 | from xml.etree.ElementTree import ElementTree
6 |
7 | def writeFasta(etree, outFile):
8 | ntaxa = len(etree.getroot().getchildren())
9 |
10 | for i in range(ntaxa):
11 | taxon = etree.getroot().getchildren()[i].get('taxon')
12 | seq = etree.getroot().getchildren()[i].get('value')
13 | outFile.write('>{}\n{}\n'.format(taxon,seq))
14 |
15 | def writeNexus(etree, outFile):
16 |
17 | # Get sequence length and taxon count
18 | ntaxa = len(etree.getroot().getchildren())
19 | nchar = len(etree.getroot().getchildren()[0].get('value'))
20 |
21 | # Write nexus boilerplate
22 | outFile.write("""#nexus
23 |
24 | Begin data;
25 | Dimensions ntax={} nchar={};
26 | Format datatype=dna symbols="ACTG" missing=? gap=-;
27 | Matrix
28 | """.format(ntaxa, nchar))
29 |
30 | # Write sequences
31 | for i in range(ntaxa):
32 | taxon = etree.getroot().getchildren()[i].get('taxon')
33 | seq = etree.getroot().getchildren()[i].get('value')
34 | outFile.write('{}\t{}\n'.format(taxon,seq))
35 |
36 | # Write end boilerplate
37 | outFile.write(";\nEnd;\n")
38 |
39 |
40 | outputFunctions = {'fasta': writeFasta, 'nexus': writeNexus}
41 |
42 |
43 | if __name__=='__main__':
44 |
45 | availableFormats = ""
46 | for fmt in outputFunctions.keys():
47 | if len(availableFormats)>0:
48 | availableFormats += ", "
49 | availableFormats += fmt
50 |
51 | parser = ArgumentParser(description="Convert alignment from BEAST 2 XML to other format.")
52 | parser.add_argument("format", type=str, help="Output format ({}).".format(availableFormats))
53 | parser.add_argument("xml_file", type=str, help="File containing alignment in BEAST 2 XML.")
54 | parser.add_argument("-o","--output", type=str, help="Optional name of output file.")
55 |
56 | if len(argv)<2:
57 | parser.print_usage()
58 | exit(0)
59 |
60 | args = parser.parse_args(argv[1:])
61 |
62 | if args.format not in outputFunctions.keys():
63 | print "Unsupported output format. Currently supported formats are: {}".format(availableFormats)
64 | exit(1)
65 |
66 | try:
67 | etree = ElementTree(file=args.xml_file)
68 | except:
69 | print "Error opening file '{}' for reading.".format(args.xml_file)
70 | exit(1)
71 |
72 | if args.output == None:
73 | outFile = stdout
74 | else:
75 | try:
76 | outFile = open(args.output, 'w')
77 | except:
78 | print "Error opening file '{}' for writing.".format(args.o)
79 | exit(1)
80 |
81 |
82 | outputFunctions.get(args.format)(etree, outFile)
83 |
84 | if args.output != None:
85 | outFile.close()
86 |
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Unit Tests'
2 | description: 'Run unit tests for MultiTypeTree'
3 | runs:
4 | using: 'docker'
5 | image: 'Dockerfile'
6 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | *.aux
3 | ColouredTree.pdf
4 | MultitypeSampler.pdf
5 | *.bbl
6 | *.blg
7 | *.bib
8 |
--------------------------------------------------------------------------------
/doc/operator_notes/SubtreeSlide.tex:
--------------------------------------------------------------------------------
1 | \documentclass[a4paper, 11pt]{article}
2 |
3 | \usepackage{amsmath}
4 |
5 | \begin{document}
6 |
7 | \section{Root move acceptance probability}
8 |
9 | The root move acts on a state vector $x=\{T;n_A,t_A,c_A;n_B,t_B,c_B\}$
10 | where $T$ is the age of the root, $n_A$ and $n_B$ are the numbers of
11 | migration events along each of the two root-connected edges, the
12 | vectors $t_A$ and $t_B$ contain the times of these events and the
13 | vectors $c_A$ and $c_B$ similarly contain the destination colours of
14 | the events.
15 |
16 | The subtree slide move draws a new state $x'=\{T',t_A,t'_B\}$
17 | from the following proposal density:
18 | \begin{align}
19 | q(x'|x) &= P(T',\vec{t}'_A,n'_A,\vec{t}'_B,n'_B|x) \nonumber \\
20 | & = P(T'|T)P(n'_A|T',T)P(n'_B|T',T)P(t_A|n'_A)P(\vec{t}_B|n'_B)
21 | \end{align}
22 |
23 | \subsection{Tree height proposal}
24 |
25 | The new tree height is selected by drawing $f'\sim g_\gamma=U(1/\gamma,\gamma)$
26 | then setting $T'=f'T$. We can then write
27 | \begin{align}
28 | P(T'|T)&=\int df'\delta(T'-f'T)g_\gamma(f')\nonumber\\
29 | &=\int_{\gamma^{-1}}^{\gamma}df'\delta(T'-f'T)\frac{1}{\gamma-\gamma^{-1}}
30 | \end{align}
31 | Performing the change of variables $f'\rightarrow z$ where $z=Tf'$
32 | allows us to evaluate this and obtain
33 | \begin{equation}
34 | P(T'|T)=\left\{\begin{array}{rl}
35 | \frac{1}{T(\gamma-\gamma^{-1})} & \text{for } \frac{T}{\gamma}\leq T' \leq\gamma T\\
36 | 0 & \text{otherwise}
37 | \end{array}\right.
38 | \end{equation}
39 |
40 | \subsection{Migration count proposal}
41 |
42 | The new migration counts $n'_A$ and $n'_B$ are chosen from Poissonian
43 | distributions with means of $T'\mu$, where $\mu$ is a tuning
44 | parameter. That is,
45 | \begin{equation}
46 | P(n'_A|T',T)=e^{-T'\mu}\frac{(T'\mu)^{n'_A}}{n'_A!}
47 | \end{equation}
48 | and similarly for $P(n'_B|T',T)$.
49 |
50 | \subsection{Migration times proposal}
51 |
52 | Each of the new migration times in $t'_A$ is chosen by drawing $n'_A$
53 | values $\tau'_A$ independently from $U(0,T')$, then sorting them from smallest
54 | to largest. If we denote the sorting function $t'_A=S(\tau'_A)$ we
55 | can write
56 | \begin{align}
57 | P(t'_A|n'_A) &= \int_{[0,T']^{n'_A}}
58 | d^{n'_A}\tau'_A\delta(t'_A-S(\tau'_A))(T')^{-n'_A}\nonumber\\
59 | &= \frac{n'_A!}{(T')^{n'_A}}
60 | \end{align}
61 | The proposal $P(t'_B|n'_B)$ is defined similarly.
62 |
63 | \subsection{Migration colours proposal}
64 |
65 | Each migration event results in a change of colour at that point in
66 | the lineage. The new colour is selected at random from those remaining
67 | after the present colour is excluded. That is
68 | \begin{equation}
69 | P(c'_A|n'_A) = \frac{1}{(N-1)^{n'_A}}
70 | \end{equation}
71 | where $N$ is the total number of available colours. $P(c'_A|n'_B)$ is
72 | defined similarly.
73 |
74 | \subsection{Full proposal}
75 |
76 | Combining these partial proposals yields the following expression for
77 | the proposal distribution:
78 | \begin{align}
79 | q(x'|x)&=
80 | \frac{1}{T(\gamma-\gamma^{-1})}I(\frac{T'}{T}\in[\frac{1}{\gamma},\gamma])\times
81 | e^{-T'\mu}\frac{(T'\mu)^{n'_A}}{n'_A!}\times
82 | \frac{n'_A!}{(T')^{n'_A}}\times \frac{1}{(N-1)^{n'_A}}\nonumber\\
83 | &\times e^{-T'\mu}\frac{(T'\mu)^{n'_B}}{n'_B!}\times
84 | \frac{n'_B!}{(T')^{n'_B}}\times \frac{1}{(N-1)^{n'_B}}\nonumber\\
85 | &=\left\{\begin{array}{rl}
86 | \frac{1}{T(\gamma-\gamma^{-1})}e^{-2T'\mu}\left(\frac{\mu}{N-1}\right)^{n'_A+n'_B} & \text{ for }
87 | \frac{T}{\gamma}\leq T' \leq T\gamma\\
88 | 0 & \text{ otherwise}
89 | \end{array}\right.
90 | \end{align}
91 |
92 | \subsection{Acceptance probability}
93 |
94 | The acceptance probability $\alpha(x'|x)$ must be defined so that
95 | \begin{equation}
96 | \int_Wdx'\int_Vdx\,q(x'|x)\alpha(x'|x)\pi(x)=\int_Wdx'\int_Vdx\,q(x|x')\alpha(x|x')\pi(x')
97 | \end{equation}
98 | Therefore we choose
99 | \begin{equation}
100 | \alpha(x'|x)=\min\left[1,\frac{\pi(x')q(x|x')}{\pi(x)q(x'|x)}\right]
101 | \end{equation}
102 |
103 | \section{Non-root move acceptance probability}
104 |
105 |
106 |
107 | \end{document}
108 |
--------------------------------------------------------------------------------
/lib/LICENSE.jblas:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009, Mikio L. Braun and contributors
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of the Technische Universität Berlin nor the
17 | names of its contributors may be used to endorse or promote
18 | products derived from this software without specific prior
19 | written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
--------------------------------------------------------------------------------
/lib/guava-15.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/lib/guava-15.0.jar
--------------------------------------------------------------------------------
/lib/jblas-1.2.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tgvaughan/MultiTypeTree/2106aefdb9de9f0d60bc3d1411a29b43a522cd21/lib/jblas-1.2.5.jar
--------------------------------------------------------------------------------
/src/multitypetree/app/beauti/InitMigrationModelConnector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Tim Vaughan (tgvaughan@gmail.com)
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.app.beauti;
18 |
19 | import beastfx.app.inputeditor.BeautiDoc;
20 | import beast.base.core.BEASTInterface;
21 | import beast.base.inference.parameter.Parameter;
22 | import beast.base.inference.parameter.RealParameter;
23 | import beast.base.evolution.likelihood.TreeLikelihood;
24 | import beast.base.evolution.tree.TraitSet;
25 | import multitypetree.evolution.tree.SCMigrationModel;
26 | import multitypetree.evolution.tree.StructuredCoalescentMultiTypeTree;
27 |
28 | import java.util.*;
29 |
30 |
31 |
32 | /**
33 | * Class containing a static method used as a "custom connector" in the
34 | * MultiTypeTree BEAUti template. This connector ensures that the
35 | * simulation used to produce the initial tree uses a migration model
36 | * containing the same rates and population sizes as the one specified
37 | * in the tree prior.
38 | *
39 | * @author Tim Vaughan (tgvaughan@gmail.com)
40 | */
41 | public class InitMigrationModelConnector {
42 |
43 | public static List uniqueTraitsInData(StructuredCoalescentMultiTypeTree scTree) {
44 | SortedSet uniqueTypes = new TreeSet<>();
45 | TraitSet typeTraitSet = scTree.typeTraitInput.get();
46 | for (String taxonName : typeTraitSet.taxaInput.get().getTaxaNames())
47 | uniqueTypes.add(typeTraitSet.getStringValue(taxonName));
48 |
49 | return new ArrayList<>(uniqueTypes);
50 | }
51 |
52 | public static boolean customConnector(BeautiDoc doc) {
53 |
54 | for (BEASTInterface p : doc.getPartitions("Tree")) {
55 | TreeLikelihood treeLikelihood = (TreeLikelihood) p;
56 | StructuredCoalescentMultiTypeTree tree =
57 | (StructuredCoalescentMultiTypeTree) treeLikelihood.treeInput.get();
58 |
59 | String pID = BeautiDoc.parsePartition(tree.getID());
60 |
61 | SCMigrationModel migModel = (SCMigrationModel)doc.pluginmap.get(
62 | "migModel.t:" + pID);
63 |
64 | SCMigrationModel migModelInit = (SCMigrationModel)doc.pluginmap.get(
65 | "migModelInit.t:" + pID);
66 |
67 | String rateMatrixStr = getParameterString((RealParameter)migModel.rateMatrixInput.get());
68 | String popSizesStr = getParameterString((RealParameter)migModel.popSizesInput.get());
69 |
70 | // Ensure model has appropriate number of demes
71 |
72 | int uniqueTraitCount = uniqueTraitsInData(tree).size();
73 | StringBuilder rateMatrixStrBuilder = new StringBuilder();
74 | StringBuilder popSizesStrBuilder = new StringBuilder();
75 |
76 | migModel.getTypeSet().initAndValidate();
77 |
78 | if (migModel.popSizesInput.get().getDimension() != migModel.getNTypes()) {
79 | for (int i=0; i) param.valuesInput.get()) {
133 | if (str.length()>0)
134 | str += " ";
135 | str += value;
136 | }
137 |
138 | return str;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/multitypetree/distributions/ExcludablePrior.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.distributions;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.core.Input.Validate;
22 | import beast.base.core.Function;
23 | import beast.base.inference.parameter.BooleanParameter;
24 | import beast.base.inference.parameter.IntegerParameter;
25 | import beast.base.inference.parameter.RealParameter;
26 | import beast.base.inference.distribution.Prior;
27 |
28 | /**
29 | * @author Tim Vaughan
30 | */
31 | @Description("Just as with Prior, produces log probability of the parameter x. "
32 | + "This variant however allows one to explicitly exclude individual "
33 | + "elements of multidimensional parameters from the result.")
34 | public class ExcludablePrior extends Prior {
35 |
36 | public Input xIncludeInput = new Input(
37 | "xInclude", "Array of true/false values specifying which elements"
38 | + " of x to include", Validate.REQUIRED);
39 |
40 | @Override
41 | public void initAndValidate() {
42 | super.initAndValidate();
43 |
44 | Function x = m_x.get();
45 | if (x instanceof RealParameter || x instanceof IntegerParameter) {
46 | if (x.getDimension() != xIncludeInput.get().getDimension())
47 | throw new IllegalArgumentException("Length of xInclude does "
48 | + "not match length of x.");
49 | }
50 | }
51 |
52 | @Override
53 | public double calculateLogP() {
54 | Function x = m_x.get();
55 | if (x instanceof RealParameter || x instanceof IntegerParameter) {
56 | // test that parameter is inside its bounds
57 | double l = 0.0;
58 | double h = 0.0;
59 | if (x instanceof RealParameter) {
60 | l = ((RealParameter) x).getLower();
61 | h = ((RealParameter) x).getUpper();
62 | } else {
63 | l = ((IntegerParameter) x).getLower();
64 | h = ((IntegerParameter) x).getUpper();
65 | }
66 | for (int i = 0; i < x.getDimension(); i++) {
67 | if (!xIncludeInput.get().getValue(i))
68 | continue;
69 | double value = x.getArrayValue(i);
70 | if (value < l || value > h) {
71 | return Double.NEGATIVE_INFINITY;
72 | }
73 | }
74 | }
75 |
76 | // Inline modified version of ParametricDistribution.calcLogP()
77 |
78 | final double fOffset = distInput.get().offsetInput.get();
79 | logP = 0;
80 | for (int i = 0; i < x.getDimension(); i++) {
81 | if (!xIncludeInput.get().getValue(i))
82 | continue;
83 | final double fX = x.getArrayValue(i) - fOffset;
84 | logP += distInput.get().logDensity(fX);
85 | }
86 |
87 | return logP;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/multitypetree/distributions/MRCATypePrior.java:
--------------------------------------------------------------------------------
1 | package multitypetree.distributions;
2 |
3 | import beast.base.core.Input;
4 | import beast.base.inference.parameter.RealParameter;
5 | import beast.base.evolution.alignment.TaxonSet;
6 | import beast.base.evolution.tree.TreeUtils;
7 | import multitypetree.evolution.tree.MigrationModel;
8 | import multitypetree.evolution.tree.MultiTypeNode;
9 |
10 | /**
11 | * @author Tim Vaughan
12 | */
13 | public class MRCATypePrior extends MultiTypeTreeDistribution {
14 |
15 | public Input taxonSetInput = new Input<>("taxonSet",
16 | "Set of taxa for which prior information is available.",
17 | Input.Validate.REQUIRED);
18 |
19 | public Input typeProbsInput = new Input<>("typeProbs",
20 | "Parameter specifying individual type probabilities.");
21 |
22 | public Input typeNameInput = new Input<>("typeName",
23 | "Name of type MRCA is constrained to be.");
24 |
25 | public Input typeInput = new Input<>("type",
26 | "Index of type MRCA is constrained to be.");
27 |
28 | public Input migrationModelInput = new Input<>("migrationModel",
29 | "Migration model");
30 |
31 | protected int type;
32 |
33 | @Override
34 | public void initAndValidate() {
35 | super.initAndValidate();
36 | if (typeProbsInput.get() != null
37 | && typeProbsInput.get().getDimension() != migrationModelInput.get().getNTypes()) {
38 | throw new IllegalArgumentException("Dimension of type probability" +
39 | " parameter must match number of types.");
40 | } else {
41 | if (typeNameInput.get() != null) {
42 | if (!mtTree.getTypeSet().getTypesAsList().contains(typeNameInput.get()))
43 | throw new IllegalArgumentException("Type set does not contain" +
44 | " type '" + typeNameInput.get() + "'.");
45 | else
46 | type = mtTree.getTypeSet().getTypeIndex(typeNameInput.get());
47 | } else {
48 | if (typeInput.get() == null)
49 | throw new IllegalArgumentException("Must specify typeProbs, " +
50 | "typeName or type inputs to MRCATypePrior.");
51 |
52 | if (typeInput.get()<0 || typeInput.get()>=migrationModelInput.get().getNTypes())
53 | throw new IllegalArgumentException("Invalid type index " +
54 | "specified for type input of MRCATypePrior.");
55 |
56 | type = typeInput.get();
57 | }
58 | }
59 | }
60 |
61 | @Override
62 | public double calculateLogP() {
63 |
64 | MultiTypeNode mrca = (MultiTypeNode)TreeUtils.getCommonAncestorNode(
65 | mtTree, taxonSetInput.get().getTaxaNames());
66 |
67 | if (typeProbsInput.get() != null)
68 | logP = Math.log(typeProbsInput.get().getValue(mrca.getNodeType()));
69 | else
70 | logP = mrca.getNodeType() == type ? 0.0 : Double.NEGATIVE_INFINITY;
71 |
72 | return logP;
73 | }
74 |
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/multitypetree/distributions/MultiTypeTreeDistribution.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.distributions;
18 |
19 | import beast.base.core.Input;
20 | import beast.base.core.Input.Validate;
21 | import beast.base.inference.Distribution;
22 | import beast.base.inference.State;
23 | import multitypetree.evolution.tree.MultiTypeTree;
24 |
25 | import java.util.ArrayList;
26 | import java.util.List;
27 | import java.util.Random;
28 |
29 | /**
30 | *
31 | * @author Tim Vaughan
32 | */
33 | public abstract class MultiTypeTreeDistribution extends Distribution {
34 |
35 | public Input mtTreeInput = new Input<>("multiTypeTree",
36 | "Multi-type tree.", Validate.REQUIRED);
37 |
38 | protected MultiTypeTree mtTree;
39 |
40 | @Override
41 | public void initAndValidate() {
42 | mtTree = mtTreeInput.get();
43 | }
44 |
45 | // Interface requirements:
46 |
47 |
48 | @Override
49 | public List getArguments() {
50 | return null;
51 | }
52 |
53 | @Override
54 | public List getConditions() {
55 | return null;
56 | }
57 |
58 | @Override
59 | public void sample(State state, Random random) {
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/multitypetree/distributions/PriorWithPole.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.distributions;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.core.Input.Validate;
22 | import beast.base.inference.parameter.RealParameter;
23 | import beast.base.inference.distribution.Prior;
24 |
25 | /**
26 | * @author Tim Vaughan
27 | */
28 | @Description("Use when a RealParameter prior has a pole at zero.")
29 | public class PriorWithPole extends Prior {
30 |
31 | public Input p0Input = new Input("p0", "Probability "
32 | + "with which each element takes the value 0.0",
33 | Validate.REQUIRED);
34 |
35 | RealParameter x;
36 | double p0;
37 |
38 | @Override
39 | public void initAndValidate() {
40 |
41 | if (!(m_x.get() instanceof RealParameter))
42 | throw new RuntimeException("PriorWithPole only applies to"
43 | + " RealParameters.");
44 |
45 | x = (RealParameter)m_x.get();
46 | p0 = p0Input.get();
47 |
48 | super.initAndValidate();
49 | }
50 |
51 | @Override
52 | public double calculateLogP() {
53 | double l = x.getLower();
54 | double h = x.getUpper();
55 |
56 | for (int i=0; ih)
59 | return Double.NEGATIVE_INFINITY;
60 | }
61 |
62 | final double offset = distInput.get().offsetInput.get();
63 | logP = 0.0;
64 | for (int i=0; i0) {
67 | value -= offset;
68 | logP += Math.log(1.0-p0) + distInput.get().logDensity(value);
69 | } else {
70 | logP += Math.log(p0);
71 | }
72 | }
73 |
74 | return logP;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/multitypetree/distributions/TypeChangeTimeCondition.java:
--------------------------------------------------------------------------------
1 | package multitypetree.distributions;
2 |
3 | import beast.base.core.Description;
4 | import beast.base.core.Input;
5 | import beast.base.inference.parameter.IntegerParameter;
6 | import beast.base.inference.parameter.RealParameter;
7 | import beast.base.evolution.tree.Node;
8 | import multitypetree.evolution.tree.MultiTypeNode;
9 |
10 | import java.util.Arrays;
11 | import java.util.HashSet;
12 | import java.util.List;
13 | import java.util.Set;
14 |
15 | /**
16 | * @author Tim Vaughan
17 | */
18 | @Description("Conditions AGAINST specific type changes in given region.")
19 | public class TypeChangeTimeCondition extends MultiTypeTreeDistribution {
20 |
21 | public Input h1Input = new Input<>(
22 | "h1",
23 | "Smaller height in height range.",
24 | new RealParameter(new Double[] {0.0}));
25 |
26 | public Input h2Input = new Input<>(
27 | "h2",
28 | "Larger height in height range.",
29 | new RealParameter(new Double[] {Double.POSITIVE_INFINITY}));
30 |
31 | public Input fromTypesInput = new Input<>(
32 | "fromTypes",
33 | "Specify type changes FROM these types.");
34 |
35 | public Input fromTypeNamesInput = new Input<>(
36 | "fromTypeNames",
37 | "Specify comma-delimited list of FROM type names.",
38 | Input.Validate.XOR, fromTypesInput);
39 |
40 | public Input toTypesInput = new Input<>(
41 | "toTypes",
42 | "Specify type changes TO these types.",
43 | Input.Validate.REQUIRED);
44 |
45 | public Input toTypeNamesInput = new Input<>(
46 | "toTypeNames",
47 | "Specify comma-delimited list of FROM type names.",
48 | Input.Validate.XOR, toTypesInput);
49 |
50 | protected Set fromTypes, toTypes;
51 | protected boolean needsUpdate;
52 |
53 | protected RealParameter h1, h2;
54 |
55 | @Override
56 | public void initAndValidate() {
57 | super.initAndValidate();
58 |
59 | h1 = h1Input.get();
60 | h2 = h2Input.get();
61 |
62 | fromTypes = new HashSet<>();
63 | toTypes = new HashSet<>();
64 |
65 | needsUpdate = true;
66 | }
67 |
68 | @Override
69 | public double calculateLogP() {
70 | update();
71 |
72 | logP = 0.0;
73 |
74 | for (Node node : mtTree.getNodesAsArray()) {
75 | if (node.isRoot())
76 | continue;
77 |
78 | if (node.getHeight()>h2.getValue()
79 | || node.getParent().getHeight()h1.getValue()
87 | && mtNode.getChangeTime(i).
16 | */
17 | package multitypetree.evolution.tree;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.evolution.tree.Tree;
22 |
23 | /**
24 | * A plugin useful for interpreting ColouredTree objects as standard BEAST
25 | * tree objects, on which single-child nodes are used to represent each
26 | * colour change.
27 | *
28 | * @author Tim Vaughan
29 | */
30 | @Description("A standard BEAST tree representation of a TreeColour object.")
31 | public class FlatMultiTypeTree extends Tree {
32 |
33 | public Input multiTypeTreeInput = new Input(
34 | "multiType", "Multi-type tree to flatten.");
35 |
36 | protected MultiTypeTree multiTypeTree;
37 |
38 | public FlatMultiTypeTree() {};
39 |
40 | @Override
41 | public void initAndValidate() {
42 | multiTypeTree = multiTypeTreeInput.get();
43 | setRoot(multiTypeTree.getFlattenedTree(false).getRoot());
44 | initArrays();
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/multitypetree/evolution/tree/MigrationModel.java:
--------------------------------------------------------------------------------
1 | package multitypetree.evolution.tree;
2 |
3 | import beast.base.core.BEASTInterface;
4 | import org.jblas.DoubleMatrix;
5 |
6 | /**
7 | * @author Tim Vaughan
8 | */
9 | public interface MigrationModel extends BEASTInterface {
10 | int getNTypes();
11 |
12 | TypeSet getTypeSet();
13 |
14 | double getBackwardRate(int i, int j);
15 |
16 | double getForwardRate(int i, int j);
17 |
18 | double getMu(boolean symmetric);
19 |
20 | DoubleMatrix getR(boolean symmetric);
21 |
22 | DoubleMatrix getQ(boolean symmetric);
23 |
24 | DoubleMatrix getRpowN(int n, boolean symmetric);
25 |
26 | int RpowSteadyN(boolean symmetric);
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/multitypetree/evolution/tree/MultiTypeTreeFromFlatTree.java:
--------------------------------------------------------------------------------
1 | package multitypetree.evolution.tree;
2 |
3 | import beast.base.core.Description;
4 | import beast.base.core.Input;
5 | import beast.base.evolution.tree.Tree;
6 |
7 | /**
8 | * @author Tim Vaughan
9 | */
10 | @Description("Class to initialise a MultiTypeTree from a " +
11 | "BEAST tree in which single-child nodes represent " +
12 | "type changes.")
13 | public class MultiTypeTreeFromFlatTree extends MultiTypeTree {
14 |
15 | public Input flatTreeInput = new Input<>(
16 | "flatTree",
17 | "Flat representation of multi-type tree.",
18 | Input.Validate.REQUIRED);
19 |
20 | @Override
21 | public void initAndValidate() {
22 | super.initAndValidate();
23 |
24 | initFromFlatTree(flatTreeInput.get(), true);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/multitypetree/evolution/tree/MultiTypeTreeFromNewick.java:
--------------------------------------------------------------------------------
1 | package multitypetree.evolution.tree;
2 |
3 |
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import beast.base.core.Description;
9 | import beast.base.core.Input;
10 | import beast.base.core.Input.Validate;
11 | import beast.base.evolution.tree.TreeParser;
12 | import beast.base.inference.StateNode;
13 | import beast.base.inference.StateNodeInitialiser;
14 |
15 | /**
16 | * @author dkuh004
17 | * Date: Jun 18, 2012
18 | * Time: 3:03:07 PM
19 | */
20 |
21 | @Description("Class to initialize a MultiTypeTree from single child newick tree with type metadata")
22 | public class MultiTypeTreeFromNewick extends MultiTypeTree implements StateNodeInitialiser {
23 |
24 | public Input newickStringInput = new Input<>("value",
25 | "Tree in Newick format.", Validate.REQUIRED);
26 |
27 | public Input adjustTipHeightsInput = new Input<>("adjustTipHeights",
28 | "Adjust tip heights in tree? Default false.", false);
29 |
30 | @Override
31 | public void initAndValidate() {
32 |
33 | super.initAndValidate();
34 |
35 | TreeParser parser = new TreeParser();
36 | parser.initByName(
37 | "IsLabelledNewick", true,
38 | "adjustTipHeights", adjustTipHeightsInput.get(),
39 | "singlechild", true,
40 | "newick", newickStringInput.get());
41 |
42 | initFromFlatTree(parser, true);
43 | }
44 |
45 | @Override
46 | public void initStateNodes() { }
47 |
48 |
49 | @Override
50 | public void getInitialisedStateNodes(List stateNodes) {
51 | stateNodes.add(this);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/multitypetree/evolution/tree/RandomMultiTypeTree.java:
--------------------------------------------------------------------------------
1 | package multitypetree.evolution.tree;
2 |
3 | import beast.base.core.Description;
4 | import beast.base.evolution.tree.Node;
5 | import beast.base.inference.StateNode;
6 | import beast.base.inference.StateNodeInitialiser;
7 | import beast.base.util.Randomizer;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * @author dkuh004
13 | * Date: Jul 16, 2012
14 | * Time: 4:22:40 PM
15 | *
16 | * May not be very useful in its current form. Need a full implementation of
17 | * RandomTree for multi-type trees.
18 | */
19 | @Description("Class to initialize a MultiTypeTree from random tree by adding minimum number of changes needed")
20 | public class RandomMultiTypeTree extends MultiTypeTree implements StateNodeInitialiser {
21 |
22 | @Override
23 | public void initAndValidate() {
24 | super.initAndValidate();
25 |
26 | if (!hasTypeTrait())
27 | throw new IllegalArgumentException("No trait set with name '" + typeLabel + "' "
28 | + "identified. Needed to specify taxon locations.");
29 |
30 | // Fill leaf colour array:
31 | for (int i = 0; i= 3){
54 | Node left = node.getChild(0);
55 | Node right = node.getChild(1);
56 |
57 | if (left.getNodeCount() >= 3) generateTyping(left);
58 | if (right.getNodeCount() >= 3) generateTyping(right);
59 |
60 | int leftCol = ((MultiTypeNode)left).getFinalType();
61 | int rightCol = ((MultiTypeNode)right).getFinalType();
62 |
63 | if (leftCol == rightCol)
64 | ((MultiTypeNode)node).setNodeType(leftCol);
65 |
66 | else {
67 |
68 | Node nodeToKeep, other;
69 | if (Randomizer.nextBoolean()) {
70 | nodeToKeep = left;
71 | other = right;
72 | } else {
73 | nodeToKeep = right;
74 | other = left;
75 | }
76 |
77 | ((MultiTypeNode)node).setNodeType(((MultiTypeNode)nodeToKeep).getNodeType());
78 |
79 | double changeTime = Randomizer.nextDouble()*(node.getHeight()-other.getHeight()) + other.getHeight();
80 | ((MultiTypeNode)other).addChange(((MultiTypeNode)node).getNodeType(), changeTime);
81 | }
82 | }
83 | }
84 |
85 |
86 |
87 | @Override
88 | public void getInitialisedStateNodes(List stateNodes) {
89 | stateNodes.add(this);
90 | }
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/multitypetree/evolution/tree/TypeSet.java:
--------------------------------------------------------------------------------
1 | package multitypetree.evolution.tree;
2 |
3 | import beast.base.core.BEASTObject;
4 | import beast.base.core.Input;
5 | import beast.base.evolution.tree.TraitSet;
6 |
7 | import java.util.*;
8 |
9 | /**
10 | * Ordered set of type names.
11 | *
12 | * @author Tim Vaughan
13 | */
14 | public class TypeSet extends BEASTObject {
15 |
16 | public Input valueInput = new Input<>("value", "Comma-delmited list of types.");
17 | public Input typeTraitSetInput = new Input<>("typeTraitSet", "Type trait set defining list of types.");
18 |
19 | protected SortedSet typeNameSet = new TreeSet<>();
20 |
21 | public TypeSet() {}
22 |
23 | /**
24 | * Constructor to produce type set containing types provided as arguments.
25 | * Useful for testing.
26 | *
27 | * @param typeNames varargs array of type names to include
28 | */
29 | public TypeSet(String ... typeNames) {
30 | typeNameSet.addAll(Arrays.asList(typeNames));
31 | }
32 |
33 | @Override
34 | public void initAndValidate() {
35 | typeNameSet.clear();
36 |
37 | if (valueInput.get() != null) {
38 | for (String typeName : valueInput.get().split(","))
39 | if (!typeName.isEmpty())
40 | typeNameSet.add(typeName);
41 | }
42 |
43 | if (typeTraitSetInput.get() != null)
44 | addTypesFromTypeTraitSet(typeTraitSetInput.get());
45 | }
46 |
47 | /**
48 | * Incorporates all of the traits present in the given trait set into the type set.
49 | *
50 | * @param typeTraitSet
51 | */
52 | public void addTypesFromTypeTraitSet(TraitSet typeTraitSet) {
53 | typeNameSet.addAll(Arrays.asList(typeTraitSet.getTaxonValues()));
54 | }
55 |
56 | /**
57 | * @return the number of unique types defined in this type set
58 | */
59 | public int getNTypes() {
60 | return Math.max(typeNameSet.size(), 2);
61 | }
62 |
63 | /**
64 | * @param typeName name of type
65 | * @return numerical index representing type
66 | */
67 | public int getTypeIndex(String typeName) {
68 | if (typeNameSet.contains(typeName))
69 | return (new ArrayList<>(typeNameSet).indexOf(typeName));
70 | else
71 | throw new IllegalArgumentException("TypeSet does not contain type with name " + typeName);
72 | }
73 |
74 | /**
75 | * @param typeIdx numerical index representing type
76 | * @return name of type
77 | */
78 | public String getTypeName(int typeIdx) {
79 | if (typeIdx(typeNameSet).get(typeIdx));
81 | else
82 | return "type_" + typeIdx;
83 | }
84 |
85 | /**
86 | * @param typeName name of type
87 | * @return true iff this TypeSet contains a type with name typeName.
88 | */
89 | public boolean containsTypeWithName(String typeName) {
90 | return typeNameSet.contains(typeName);
91 | }
92 |
93 | /**
94 | * @return list of type names ordered according to type index
95 | */
96 | public List getTypesAsList() {
97 | return new ArrayList<>(typeNameSet);
98 | }
99 |
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/MultiTypeUniform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 |
20 | import beast.base.core.Description;
21 | import beast.base.core.Input;
22 | import beast.base.evolution.tree.Node;
23 | import beast.base.util.Randomizer;
24 | import multitypetree.evolution.tree.MultiTypeNode;
25 |
26 | /**
27 | * @author Denise Kuhnert
28 | */
29 | @Description("Randomly selects true internal tree node (i.e. not the root) and"
30 | + " moves node height uniformly in interval restricted by the node's"
31 | + " parent and children.")
32 | public class MultiTypeUniform extends MultiTypeTreeOperator {
33 |
34 | public Input includeRootInput = new Input<>("includeRoot",
35 | "Allow modification of root node.", false);
36 |
37 | public Input rootScaleFactorInput = new Input<>("rootScaleFactor",
38 | "Root scale factor.", 0.9);
39 |
40 | /**
41 | * Change the node height and return the hastings ratio.
42 | *
43 | * @return log of Hastings Ratio
44 | */
45 | @Override
46 | public double proposal() {
47 | // Randomly select event on tree:
48 | int event = Randomizer.nextInt(mtTree.getInternalNodeCount() + mtTree.getTotalNumberOfChanges());
49 |
50 |
51 | MultiTypeNode node = null;
52 | int changeIdx = -1;
53 | if (event0
94 | ? node.getChangeTime(0)
95 | : node.getParent().getHeight();
96 |
97 | double u = Randomizer.nextDouble();
98 | double tnew = u*tmin + (1.0-u)*tmax;
99 |
100 | node.setHeight(tnew);
101 | return 0.0;
102 | }
103 | } else {
104 | double tmin, tmax;
105 | if (changeIdx+1
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.evolution.tree.Node;
21 | import beast.base.util.Randomizer;
22 | import multitypetree.evolution.tree.MultiTypeNode;
23 |
24 | /**
25 | * @author Tim Vaughan
26 | */
27 | @Description("Retypes a randomly chosen node and its attached branches. "
28 | + "This variant uses the uniformization branch retyping procedure.")
29 | public class NodeRetype extends UniformizationRetypeOperator {
30 |
31 | @Override
32 | public double proposal() {
33 | double logHR = 0.0;
34 |
35 | // Select node:
36 | Node node = mtTree.getNode(mtTree.getLeafNodeCount()
37 | + Randomizer.nextInt(mtTree.getInternalNodeCount()));
38 |
39 | // Record probability of current types along attached branches:
40 | if (!node.isRoot())
41 | logHR += getBranchTypeProb(node);
42 |
43 | logHR += getBranchTypeProb(node.getLeft())
44 | + getBranchTypeProb(node.getRight());
45 |
46 | // Select new node type:
47 | ((MultiTypeNode)node).setNodeType(
48 | Randomizer.nextInt(migModel.getNTypes()));
49 |
50 | // Retype attached branches:
51 | try {
52 | if (!node.isRoot())
53 | logHR -= retypeBranch(node);
54 |
55 | logHR -= retypeBranch(node.getLeft())
56 | + retypeBranch(node.getRight());
57 | } catch (NoValidPathException e) {
58 | return Double.NEGATIVE_INFINITY;
59 | }
60 |
61 |
62 | return logHR;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/NodeRetypeRandom.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.evolution.tree.Node;
21 | import beast.base.evolution.tree.Tree;
22 | import beast.base.util.Randomizer;
23 | import multitypetree.evolution.tree.MultiTypeNode;
24 |
25 | /**
26 | * @author Tim Vaughan
27 | */
28 | @Description("Retypes a randomly chosen node and its attached branches. "
29 | + "This variant uses an unconditioned random walk for branch retyping.")
30 | public class NodeRetypeRandom extends RandomRetypeOperator {
31 |
32 | @Override
33 | public double proposal() {
34 | double logHR = 0.0;
35 |
36 | // Select node:
37 | Node node;
38 | do {
39 | node = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
40 | } while (node.isLeaf());
41 |
42 | // Record probability of current types along attached branches:
43 | if (!node.isRoot())
44 | logHR += getBranchTypeProb(node);
45 |
46 | logHR += getBranchTypeProb(node.getLeft())
47 | + getBranchTypeProb(node.getRight());
48 |
49 | // Select new node type:
50 | ((MultiTypeNode)node).setNodeType(Randomizer.nextInt(migModel.getNTypes()));
51 |
52 | // Retype attached branches, forcing reject if inconsistent:
53 | if (!node.isRoot()) {
54 | logHR -= retypeBranch(node);
55 |
56 | if (((MultiTypeNode)node).getFinalType() != ((MultiTypeNode)node.getParent()).getNodeType())
57 | return Double.NEGATIVE_INFINITY;
58 | }
59 |
60 | logHR -= retypeBranch(node.getLeft())
61 | + retypeBranch(node.getRight());
62 |
63 | if ((((MultiTypeNode)node.getLeft()).getFinalType() != ((MultiTypeNode)node).getNodeType())
64 | || (((MultiTypeNode)node.getRight()).getFinalType() != ((MultiTypeNode)node).getNodeType()))
65 | return Double.NEGATIVE_INFINITY;
66 |
67 | // WHY IS THIS NECESSARY!?
68 | node.makeDirty(Tree.IS_DIRTY);
69 | node.getLeft().makeDirty(Tree.IS_DIRTY);
70 | node.getRight().makeDirty(Tree.IS_DIRTY);
71 |
72 | return logHR;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/NodeShiftRetype.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.evolution.tree.Node;
22 | import beast.base.util.Randomizer;
23 | import multitypetree.evolution.tree.MultiTypeNode;
24 |
25 | /**
26 | * @author Tim Vaughan
27 | */
28 | @Description("Operator implementing a very similar move to MultiTypeUniform, "
29 | + " with the difference that this operator draws new node positions"
30 | + " uniformly between the parent and oldest child heights and"
31 | + " retypes the modified branches. Additionally, this operator"
32 | + " can act on the root node.")
33 | public class NodeShiftRetype extends UniformizationRetypeOperator {
34 |
35 | public Input rootOnlyInput = new Input<>("rootOnly",
36 | "Always select root node for height adjustment.", false);
37 |
38 | public Input noRootInput = new Input<>("noRoot",
39 | "Never select root node for height adjustment.", false);
40 |
41 | public Input rootScaleFactorInput = new Input<>("rootScaleFactor",
42 | "Scale factor used in root height proposals. (Default 0.8)", 0.8);
43 |
44 | @Override
45 | public void initAndValidate() {
46 | super.initAndValidate();
47 |
48 | if (rootOnlyInput.get() && noRootInput.get())
49 | throw new IllegalArgumentException("rootOnly and noRoot inputs "
50 | + "cannot both be set to true simultaneously.");
51 | }
52 |
53 | @Override
54 | public double proposal() {
55 | // Select internal node to adjust:
56 | Node node;
57 | if (rootOnlyInput.get())
58 | node = mtTree.getRoot();
59 | else
60 | do {
61 | node = mtTree.getNode(mtTree.getLeafNodeCount()
62 | + Randomizer.nextInt(mtTree.getInternalNodeCount()));
63 | } while (noRootInput.get() && node.isRoot());
64 |
65 |
66 | // Generate relevant proposal:
67 | if (node.isRoot())
68 | return rootProposal(node);
69 | else
70 | return nonRootProposal(node);
71 | }
72 |
73 | /**
74 | * Root node proposal.
75 | * @param root
76 | * @return log of HR
77 | */
78 | private double rootProposal(Node root) {
79 |
80 | double logHR = 0.0;
81 |
82 | // Record probability of current typing:
83 | logHR += getBranchTypeProb(root.getLeft())
84 | + getBranchTypeProb(root.getRight());
85 |
86 | // Select new root height:
87 | double u = Randomizer.nextDouble();
88 | double f = u*rootScaleFactorInput.get() + (1-u)/rootScaleFactorInput.get();
89 | double oldestChildHeight = Math.max(
90 | root.getLeft().getHeight(),
91 | root.getRight().getHeight());
92 | root.setHeight(oldestChildHeight + f*(root.getHeight()-oldestChildHeight));
93 | logHR -= Math.log(f);
94 |
95 | // Select new root node type:
96 | ((MultiTypeNode)root).setNodeType(Randomizer.nextInt(migModel.getNTypes()));
97 |
98 | // Recolour branches below root:
99 | try {
100 | logHR -= retypeBranch(root.getLeft())
101 | + retypeBranch(root.getRight());
102 | } catch (NoValidPathException e) {
103 | return Double.NEGATIVE_INFINITY;
104 | }
105 |
106 | return logHR;
107 | }
108 |
109 | /**
110 | * Non-root internal node proposal.
111 | * @param node
112 | * @return log of HR of move
113 | */
114 | private double nonRootProposal(Node node) {
115 |
116 | double logHR = 0.0;
117 |
118 | // Record probability of current colouring:
119 | logHR += getBranchTypeProb(node)
120 | + getBranchTypeProb(node.getLeft())
121 | + getBranchTypeProb(node.getRight());
122 |
123 | // Select new node height:
124 | double upperBound = node.getParent().getHeight();
125 | double lowerBound = Math.max(
126 | node.getLeft().getHeight(),
127 | node.getRight().getHeight());
128 | node.setHeight(lowerBound+(upperBound-lowerBound)*Randomizer.nextDouble());
129 |
130 | // Select new node colour:
131 | ((MultiTypeNode)node).setNodeType(Randomizer.nextInt(migModel.getNTypes()));
132 |
133 | // Recolour branches connected to node:
134 | try {
135 | logHR -= retypeBranch(node)
136 | + retypeBranch(node.getLeft())
137 | + retypeBranch(node.getRight());
138 | } catch (NoValidPathException e) {
139 | return Double.NEGATIVE_INFINITY;
140 | }
141 |
142 | return logHR;
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/NodeShiftRetypeRandom.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.evolution.tree.Node;
22 | import beast.base.util.Randomizer;
23 | import multitypetree.evolution.tree.MultiTypeNode;
24 |
25 | /**
26 | * @author Tim Vaughan
27 | */
28 | @Description("Operator implementing a very similar move to MultiTypeUniform, "
29 | + " with the difference that this operator draws new node positions"
30 | + " uniformly between the parent and oldest child heights and"
31 | + " retypes the modified branches. Additionally, this operator"
32 | + " can act on the root node.")
33 | public class NodeShiftRetypeRandom extends RandomRetypeOperator {
34 |
35 | public Input rootOnlyInput = new Input<>("rootOnly",
36 | "Always select root node for height adjustment.", false);
37 |
38 | public Input noRootInput = new Input<>("noRoot",
39 | "Never select root node for height adjustment.", false);
40 |
41 | public Input rootScaleFactorInput = new Input<>("rootScaleFactor",
42 | "Scale factor used in root height proposals. (Default 0.8)", 0.8);
43 |
44 | @Override
45 | public void initAndValidate() {
46 | super.initAndValidate();
47 |
48 | if (rootOnlyInput.get() && noRootInput.get())
49 | throw new IllegalArgumentException("rootOnly and noRoot inputs "
50 | + "cannot both be set to true simultaneously.");
51 | }
52 |
53 | @Override
54 | public double proposal() {
55 | // Select internal node to adjust:
56 | Node node;
57 | if (rootOnlyInput.get())
58 | node = mtTree.getRoot();
59 | else
60 | do {
61 | node = mtTree.getNode(mtTree.getLeafNodeCount()
62 | + Randomizer.nextInt(mtTree.getInternalNodeCount()));
63 | } while (noRootInput.get() && node.isRoot());
64 |
65 |
66 | // Generate relevant proposal:
67 | if (node.isRoot())
68 | return rootProposal(node);
69 | else
70 | return nonRootProposal(node);
71 | }
72 |
73 | /**
74 | * Root node proposal.
75 | * @param root
76 | * @return log of HR
77 | */
78 | private double rootProposal(Node root) {
79 |
80 | double logHR = 0.0;
81 |
82 | // Record probability of current colouring:
83 | logHR += getBranchTypeProb(root.getLeft())
84 | + getBranchTypeProb(root.getRight());
85 |
86 | // Select new root height:
87 | double u = Randomizer.nextDouble();
88 | double f = u*rootScaleFactorInput.get() + (1-u)/rootScaleFactorInput.get();
89 | double oldestChildHeight = Math.max(
90 | root.getLeft().getHeight(),
91 | root.getRight().getHeight());
92 | root.setHeight(oldestChildHeight + f*(root.getHeight()-oldestChildHeight));
93 | logHR -= Math.log(f);
94 |
95 | // Select new root node colour:
96 | ((MultiTypeNode)root).setNodeType(Randomizer.nextInt(migModel.getNTypes()));
97 |
98 | // Recolour branches below root:
99 | logHR -= retypeBranch(root.getLeft())
100 | + retypeBranch(root.getRight());
101 |
102 | // Reject if new colouring inconsistent:
103 | if ((((MultiTypeNode)root.getLeft()).getFinalType() != ((MultiTypeNode)root).getNodeType())
104 | || (((MultiTypeNode)root.getRight()).getFinalType() != ((MultiTypeNode)root).getNodeType()))
105 | return Double.NEGATIVE_INFINITY;
106 |
107 | return logHR;
108 | }
109 |
110 | /**
111 | * Non-root internal node proposal.
112 | * @param node
113 | * @return log of HR of move
114 | */
115 | private double nonRootProposal(Node node) {
116 |
117 | double logHR = 0.0;
118 |
119 | // Record probability of current colouring:
120 | logHR += getBranchTypeProb(node)
121 | + getBranchTypeProb(node.getLeft())
122 | + getBranchTypeProb(node.getRight());
123 |
124 | // Select new node height:
125 | double upperBound = node.getParent().getHeight();
126 | double lowerBound = Math.max(
127 | node.getLeft().getHeight(),
128 | node.getRight().getHeight());
129 | node.setHeight(lowerBound+(upperBound-lowerBound)*Randomizer.nextDouble());
130 |
131 | // Select new node colour:
132 | ((MultiTypeNode)node).setNodeType(Randomizer.nextInt(migModel.getNTypes()));
133 |
134 | // Recolour branches connected to node:
135 | logHR -= retypeBranch(node)
136 | + retypeBranch(node.getLeft())
137 | + retypeBranch(node.getRight());
138 |
139 | // Reject if new colouring inconsistent:
140 | if ((((MultiTypeNode)node.getLeft()).getFinalType() != ((MultiTypeNode)node).getNodeType())
141 | || (((MultiTypeNode)node.getRight()).getFinalType() != ((MultiTypeNode)node).getNodeType())
142 | || (((MultiTypeNode)node).getFinalType() != ((MultiTypeNode)node.getParent()).getNodeType()))
143 | return Double.NEGATIVE_INFINITY;
144 |
145 | return logHR;
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/RandomRetypeOperator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Input;
20 | import beast.base.evolution.tree.Node;
21 | import beast.base.util.Randomizer;
22 | import multitypetree.evolution.tree.MultiTypeNode;
23 |
24 | /**
25 | * Abstract class of operators on MultiTypeTrees which retype branches using a
26 | * fixed-rate continuous time random walk across demes.
27 | *
28 | * @author Tim Vaughan
29 | */
30 | public abstract class RandomRetypeOperator extends MultiTypeTreeOperator {
31 |
32 | public Input muInput = new Input<>("mu",
33 | "Migration rate for proposal distribution", Input.Validate.REQUIRED);
34 |
35 | /**
36 | * Retype branch between srcNode and its parent with rate fixed by the
37 | * tuning parameter mu.
38 | *
39 | * @param srcNode
40 | * @return Probability of branch typing
41 | */
42 | protected double retypeBranch(Node srcNode) {
43 |
44 | double mu = muInput.get();
45 |
46 | Node srcNodeParent = srcNode.getParent();
47 | double t_srcNode = srcNode.getHeight();
48 | double t_srcNodeParent = srcNodeParent.getHeight();
49 |
50 | int srcNodeType = ((MultiTypeNode)srcNode).getNodeType();
51 |
52 | // Clear existing changes in preparation for adding replacements:
53 | ((MultiTypeNode)srcNode).clearChanges();
54 |
55 | double t = t_srcNode;
56 | int lastType = srcNodeType;
57 | while (t < t_srcNodeParent) {
58 |
59 | // Determine time to next migration event:
60 | t += Randomizer.nextExponential(mu);
61 |
62 | if (t < t_srcNodeParent) {
63 |
64 | // Select new colour:
65 | int newType = Randomizer.nextInt(migModel.getNTypes() - 1);
66 | if (newType >= lastType)
67 | newType += 1;
68 | ((MultiTypeNode)srcNode).addChange(newType, t);
69 |
70 | lastType = newType;
71 | }
72 | }
73 |
74 | // Return log of branch type probability:
75 | return -mu*(t_srcNodeParent - t_srcNode)
76 | + ((MultiTypeNode)srcNode).getChangeCount()*Math.log(mu/(migModel.getNTypes()-1));
77 |
78 | }
79 |
80 | /**
81 | * Get probability of the colouring along the branch between srcNode
82 | * and its parent.
83 | *
84 | * @param srcNode
85 | * @return Probability of the colouring.
86 | */
87 | protected double getBranchTypeProb(Node srcNode) {
88 |
89 | double mu = muInput.get();
90 | double T = srcNode.getParent().getHeight()
91 | - srcNode.getHeight();
92 | int n = ((MultiTypeNode)srcNode).getChangeCount();
93 | int N = migModel.getNTypes();
94 |
95 | if (N == 0)
96 | return 0.0;
97 | else
98 | return -mu*T + n*Math.log(mu/(N-1));
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/SpecialTypeBirthDeath.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.util.Randomizer;
21 | import multitypetree.evolution.tree.MultiTypeNode;
22 |
23 | import java.util.HashSet;
24 | import java.util.Set;
25 |
26 | /**
27 | *
28 | * @author Tim Vaughan
29 | */
30 | @Description("Special move specific to two taxon trees for debugging only.")
31 | public class SpecialTypeBirthDeath extends MultiTypeTreeOperator {
32 |
33 | @Override
34 | public double proposal() {
35 | if (mtTree.getLeafNodeCount() != 2)
36 | throw new IllegalArgumentException("SpecialTypeBirthDeath only valid for 2 taxon trees.");
37 |
38 | // Cannot produce or operate on trees without any changes
39 | if (mtTree.getTotalNumberOfChanges()==0)
40 | return Double.NEGATIVE_INFINITY;
41 |
42 | //String startTree = mtTree.toString();
43 |
44 | MultiTypeNode root = (MultiTypeNode)mtTree.getRoot();
45 | MultiTypeNode left = (MultiTypeNode)root.getLeft();
46 | MultiTypeNode right = (MultiTypeNode)root.getRight();
47 |
48 | // Select event:
49 | int event = Randomizer.nextInt(mtTree.getTotalNumberOfChanges());
50 |
51 | MultiTypeNode node, sister;
52 | int changeIdx;
53 | if (event illegalTypesBirth = new HashSet();
117 |
118 | illegalTypesBirth.add(node.getChangeType(changeIdx));
119 | if (changeIdx>0)
120 | illegalTypesBirth.add(node.getChangeType(changeIdx-1));
121 | else
122 | illegalTypesBirth.add(node.getNodeType());
123 |
124 | tmin = node.getChangeTime(changeIdx);
125 |
126 | if (changeIdx+1>=node.getChangeCount()) {
127 | tmax = node.getParent().getHeight();
128 | } else
129 | tmax = node.getChangeTime(changeIdx+1);
130 |
131 |
132 | // Backward move probability:
133 | logHR += Math.log(1.0/(mtTree.getTotalNumberOfChanges()+1));
134 |
135 | // Forward move probability:
136 | int Cbirth = migModel.getNTypes() - illegalTypesBirth.size();
137 | logHR -= Math.log(1.0/(Cbirth*mtTree.getTotalNumberOfChanges()*(tmax-tmin)));
138 |
139 | // Add new event:
140 | double tnew = tmin + Randomizer.nextDouble()*(tmax-tmin);
141 | int aboveType = node.getChangeType(changeIdx);
142 | node.insertChange(changeIdx+1, aboveType, tnew);
143 |
144 | // Select and apply new type:
145 | int n = Randomizer.nextInt(Cbirth);
146 | int changeType;
147 | for (changeType = 0; changeType=node.getChangeCount())
165 | return Double.NEGATIVE_INFINITY;
166 |
167 | double logHR = 0.0;
168 |
169 | double tmin, tmax;
170 |
171 | Set illegalTypesBirth = new HashSet();
172 |
173 | illegalTypesBirth.add(node.getChangeType(changeIdx+1));
174 | if (changeIdx>0)
175 | illegalTypesBirth.add(node.getChangeType(changeIdx-1));
176 | else
177 | illegalTypesBirth.add(node.getNodeType());
178 |
179 | tmin = node.getChangeTime(changeIdx);
180 |
181 | if (changeIdx+2>=node.getChangeCount())
182 | tmax = node.getParent().getHeight();
183 | else
184 | tmax = node.getChangeTime(changeIdx+2);
185 |
186 | // Backward move probability:
187 | int Cbirth = migModel.getNTypes() - illegalTypesBirth.size();
188 | logHR += Math.log(1.0/(Cbirth*(mtTree.getTotalNumberOfChanges()-1)*(tmax-tmin)));
189 |
190 | // Forward move probability:
191 | logHR -= Math.log(1.0/mtTree.getTotalNumberOfChanges());
192 |
193 | // Record colour above node to remove:
194 | int changeType = node.getChangeType(changeIdx+1);
195 |
196 | // Remove change:
197 | node.removeChange(changeIdx+1);
198 |
199 | // Update colouring
200 | node.setChangeType(changeIdx, changeType);
201 |
202 | return logHR;
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/TypePairBirthDeath.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.evolution.tree.Node;
21 | import beast.base.util.Randomizer;
22 | import multitypetree.evolution.tree.MultiTypeNode;
23 |
24 | /**
25 | * @author Tim Vaughan
26 | */
27 | @Description("Implements type change (migration) pair birth/death move "
28 | + "described by Ewing et al., Genetics (2004).")
29 | public class TypePairBirthDeath extends MultiTypeTreeOperator {
30 |
31 | @Override
32 | public double proposal() {
33 | int n = mtTree.getLeafNodeCount();
34 | int m = mtTree.getTotalNumberOfChanges();
35 |
36 | // Select sub-edge at random:
37 | int edgeNum = Randomizer.nextInt(2*n - 2 + m);
38 |
39 | // Find edge that sub-edge lies on:
40 | Node selectedNode = null;
41 | for (Node node : mtTree.getNodesAsArray()) {
42 | if (node.isRoot())
43 | continue;
44 |
45 | if (edgeNum<((MultiTypeNode)node).getChangeCount()+1) {
46 | selectedNode = node;
47 | break;
48 | }
49 | edgeNum -= ((MultiTypeNode)node).getChangeCount()+1;
50 | }
51 |
52 | // Complete either pair birth or pair death proposal:
53 | if (Randomizer.nextDouble()<0.5)
54 | return birthProposal(selectedNode, edgeNum, n, m);
55 | else
56 | return deathProposal(selectedNode, edgeNum, n, m);
57 |
58 | }
59 |
60 | /**
61 | * Type change pair birth proposal.
62 | *
63 | * @param node Node above which selected edge lies
64 | * @param edgeNum Number of selected edge
65 | * @param n Number of nodes on tree.
66 | * @param m Number of type changes currently on tree.
67 | * @return log of Hastings factor of move.
68 | */
69 | private double birthProposal(Node node, int edgeNum, int n, int m) {
70 |
71 | MultiTypeNode mtNode = (MultiTypeNode)node;
72 |
73 | int ridx = edgeNum;
74 | int sidx = edgeNum-1;
75 |
76 | double ts, tr;
77 | int oldEdgeType;
78 | if (sidx<0) {
79 | ts = node.getHeight();
80 | oldEdgeType = mtNode.getNodeType();
81 | } else {
82 | ts = mtNode.getChangeTime(sidx);
83 | oldEdgeType = mtNode.getChangeType(sidx);
84 | }
85 |
86 | if (ridx>mtNode.getChangeCount()-1)
87 | tr = node.getParent().getHeight();
88 | else
89 | tr = mtNode.getChangeTime(ridx);
90 |
91 | int newEdgeType;
92 | do {
93 | newEdgeType = Randomizer.nextInt(migModel.getNTypes());
94 | } while (newEdgeType == oldEdgeType);
95 |
96 | double tau1 = Randomizer.nextDouble()*(tr-ts) + ts;
97 | double tau2 = Randomizer.nextDouble()*(tr-ts) + ts;
98 | double tauMin = Math.min(tau1, tau2);
99 | double tauMax = Math.max(tau1, tau2);
100 |
101 | mtNode.insertChange(edgeNum, oldEdgeType, tauMax);
102 | mtNode.insertChange(edgeNum, newEdgeType, tauMin);
103 |
104 | return Math.log((migModel.getNTypes()-1)*(m + 2*n - 2)*(tr-ts)*(tr-ts))
105 | - Math.log(2*(m + 2*n));
106 | }
107 |
108 | /**
109 | * Colour change pair death proposal.
110 | *
111 | * @param node Node above which selected edge lies
112 | * @param edgeNum Number of selected edge
113 | * @param n Number of nodes on tree
114 | * @param m Number of colour changes currently on tree
115 | * @return log of Hastings factor of move.
116 | */
117 | private double deathProposal(Node node, int edgeNum, int n, int m) {
118 |
119 | MultiTypeNode mtNode = (MultiTypeNode)node;
120 |
121 | int idx = edgeNum-1;
122 | int sidx = edgeNum-2;
123 | int ridx = edgeNum+1;
124 |
125 | if (sidx<-1 || ridx > mtNode.getChangeCount())
126 | return Double.NEGATIVE_INFINITY;
127 |
128 | double ts, tr;
129 | int is, ir;
130 | if (sidx<0) {
131 | ts = node.getHeight();
132 | is = mtNode.getNodeType();
133 | } else {
134 | ts = mtNode.getChangeTime(sidx);
135 | is = mtNode.getChangeType(sidx);
136 | }
137 |
138 | if (ridx>mtNode.getChangeCount()-1)
139 | tr = node.getParent().getHeight();
140 | else
141 | tr = mtNode.getChangeTime(ridx);
142 | ir = mtNode.getChangeType(ridx-1);
143 |
144 | if (is != ir)
145 | return Double.NEGATIVE_INFINITY;
146 |
147 | mtNode.removeChange(idx);
148 | mtNode.removeChange(idx);
149 |
150 | return Math.log(2*(m + 2*n - 2))
151 | - Math.log((migModel.getNTypes()-1)*(m+2*n-4)*(tr-ts)*(tr-ts));
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/TypedSubtreeExchange.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.evolution.tree.Node;
22 | import beast.base.util.Randomizer;
23 |
24 | /**
25 | * @author Tim Vaughan
26 | */
27 | @Description("Subtree/branch exchange operator for coloured trees. This"
28 | + " is the `uniformized recolouring' variant where new branch colourings"
29 | + " are selected using random walk conditional on the colours at both"
30 | + " ends of the branch.")
31 | public class TypedSubtreeExchange extends UniformizationRetypeOperator {
32 |
33 | public Input isNarrowInput = new Input("isNarrow",
34 | "Whether or not to use narrow exchange. (Default true.)", true);
35 |
36 | @Override
37 | public double proposal() {
38 | double logHR = 0.0;
39 |
40 | // Select source and destination nodes:
41 |
42 | Node srcNode, srcNodeParent, destNode, destNodeParent;
43 | if (isNarrowInput.get()) {
44 |
45 | // Narrow exchange selection:
46 | do {
47 | srcNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
48 | } while (srcNode.isRoot() || srcNode.getParent().isRoot());
49 | srcNodeParent = srcNode.getParent();
50 | destNode = getOtherChild(srcNodeParent.getParent(), srcNodeParent);
51 | destNodeParent = destNode.getParent();
52 |
53 | } else {
54 |
55 | // Wide exchange selection:
56 | do {
57 | srcNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
58 | } while (srcNode.isRoot());
59 | srcNodeParent = srcNode.getParent();
60 |
61 | do {
62 | destNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
63 | } while(destNode == srcNode
64 | || destNode.isRoot()
65 | || destNode.getParent() == srcNode.getParent());
66 | destNodeParent = destNode.getParent();
67 | }
68 |
69 | // Reject if substitution would result in negative branch lengths:
70 | if (destNode.getHeight()>srcNodeParent.getHeight()
71 | || srcNode.getHeight()>destNodeParent.getHeight())
72 | return Double.NEGATIVE_INFINITY;
73 |
74 | // Record probability of old colours:
75 | logHR += getBranchTypeProb(srcNode) + getBranchTypeProb(destNode);
76 |
77 | // Make changes to tree topology:
78 | replace(srcNodeParent, srcNode, destNode);
79 | replace(destNodeParent, destNode, srcNode);
80 |
81 | // Recolour branches involved:
82 | try {
83 | logHR -= retypeBranch(srcNode) + retypeBranch(destNode);
84 | } catch (NoValidPathException e) {
85 | return Double.NEGATIVE_INFINITY;
86 | }
87 |
88 | return logHR;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/TypedSubtreeExchangeEasy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.evolution.tree.Node;
22 | import beast.base.util.Randomizer;
23 |
24 | /**
25 | * @author Tim Vaughan
26 | */
27 | @Description("Subtree/branch exchange operator for coloured trees. This"
28 | + " is the `no recolouring' variant where the new topology is selected"
29 | + " irrespective of the colouring of the branches involved. Used for"
30 | + " testing Ewing et al.'s sampler moves.")
31 | public class TypedSubtreeExchangeEasy extends MultiTypeTreeOperator {
32 |
33 | public Input isNarrowInput = new Input<>("isNarrow",
34 | "Whether or not to use narrow exchange. (Default true.)", true);
35 |
36 | @Override
37 | public double proposal() {
38 | // Select source and destination nodes:
39 |
40 | Node srcNode, srcNodeParent, destNode, destNodeParent;
41 | if (isNarrowInput.get()) {
42 |
43 | // Narrow exchange selection:
44 | do {
45 | srcNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
46 | } while (srcNode.isRoot() || srcNode.getParent().isRoot());
47 | srcNodeParent = srcNode.getParent();
48 | destNode = getOtherChild(srcNodeParent.getParent(), srcNodeParent);
49 | destNodeParent = destNode.getParent();
50 |
51 | } else {
52 |
53 | // Wide exchange selection:
54 | do {
55 | srcNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
56 | } while (srcNode.isRoot());
57 | srcNodeParent = srcNode.getParent();
58 |
59 | do {
60 | destNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
61 | } while(destNode == srcNode
62 | || destNode.isRoot()
63 | || destNode.getParent() == srcNodeParent);
64 | destNodeParent = destNode.getParent();
65 |
66 | // Explicitly reject outrageous node selections:
67 | // (Dangerous to make this a condition of destNode selection,
68 | // as doing so can lead to infinite loops.)
69 | if (srcNodeParent == destNode || destNodeParent == srcNode)
70 | return Double.NEGATIVE_INFINITY;
71 | }
72 |
73 | // Reject outright if substitution would result in negative branch
74 | // lengths:
75 | if (destNode.getHeight()>srcNodeParent.getHeight()
76 | || srcNode.getHeight()>destNodeParent.getHeight())
77 | return Double.NEGATIVE_INFINITY;
78 |
79 | // Make changes to tree topology:
80 | replace(srcNodeParent, srcNode, destNode);
81 | replace(destNodeParent, destNode, srcNode);
82 |
83 | // Force rejection if resulting multi-type tree invalid:
84 | if (!mtTree.isValid())
85 | return Double.NEGATIVE_INFINITY;
86 |
87 | return 0.0;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/TypedSubtreeExchangeRandom.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.evolution.tree.Node;
22 | import beast.base.util.Randomizer;
23 | import multitypetree.evolution.tree.MultiTypeNode;
24 |
25 | /**
26 | * @author Tim Vaughan
27 | */
28 | @Description("Subtree/branch exchange operator for coloured trees. This"
29 | + " is the `random recolouring' variant where new branch colourings"
30 | + " are selected using an unconditioned random walk. This will likely"
31 | + " be very inefficient as this operator requires recolouring of"
32 | + " two branches, meaning that the acceptance probability goes as"
33 | + " the _square_ of the inverse of the number of colours.")
34 | public class TypedSubtreeExchangeRandom extends RandomRetypeOperator {
35 |
36 | public Input isNarrowInput = new Input("isNarrow",
37 | "Whether or not to use narrow exchange. (Default true.)", true);
38 |
39 | @Override
40 | public double proposal() {
41 | double logHR = 0.0;
42 |
43 | // Select source and destination nodes:
44 |
45 | Node srcNode, srcNodeParent, destNode, destNodeParent;
46 | if (isNarrowInput.get()) {
47 |
48 | // Narrow exchange selection:
49 | do {
50 | srcNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
51 | } while (srcNode.isRoot() || srcNode.getParent().isRoot());
52 | srcNodeParent = srcNode.getParent();
53 | destNode = getOtherChild(srcNodeParent.getParent(), srcNodeParent);
54 | destNodeParent = destNode.getParent();
55 |
56 | } else {
57 |
58 | // Wide exchange selection:
59 | do {
60 | srcNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
61 | } while (srcNode.isRoot());
62 | srcNodeParent = srcNode.getParent();
63 |
64 | do {
65 | destNode = mtTree.getNode(Randomizer.nextInt(mtTree.getNodeCount()));
66 | } while(destNode == srcNode
67 | || destNode.isRoot()
68 | || destNode.getParent() == srcNode.getParent());
69 | destNodeParent = destNode.getParent();
70 | }
71 |
72 | // Reject outright if substitution would result in negative branch
73 | // lengths:
74 | if (destNode.getHeight()>srcNodeParent.getHeight()
75 | || srcNode.getHeight()>destNodeParent.getHeight())
76 | return Double.NEGATIVE_INFINITY;
77 |
78 | // Record probability of old colours:
79 | logHR += getBranchTypeProb(srcNode) + getBranchTypeProb(destNode);
80 |
81 | // Make changes to tree topology:
82 | replace(srcNodeParent, srcNode, destNode);
83 | replace(destNodeParent, destNode, srcNode);
84 |
85 | // Recolour branches involved:
86 | logHR -= retypeBranch(srcNode) + retypeBranch(destNode);
87 |
88 | // Force rejection if colouring inconsistent:
89 | if ((((MultiTypeNode)srcNode).getFinalType() != ((MultiTypeNode)destNodeParent).getNodeType())
90 | || (((MultiTypeNode)destNode).getFinalType() != ((MultiTypeNode)srcNodeParent).getNodeType()))
91 | return Double.NEGATIVE_INFINITY;
92 |
93 | return logHR;
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/multitypetree/operators/ZeroJump.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Input;
21 | import beast.base.core.Input.Validate;
22 | import beast.base.inference.Operator;
23 | import beast.base.inference.parameter.RealParameter;
24 | import beast.base.util.Randomizer;
25 |
26 | /**
27 | * @author Tim Vaughan
28 | */
29 | @Description("Reversibly sets a RealParameter element to zero. Used for"
30 | + " variable selection.")
31 | public class ZeroJump extends Operator {
32 |
33 | public Input parameterInput = new Input<>(
34 | "parameter", "RealParameter to operate on.", Validate.REQUIRED);
35 |
36 | public Input alphaInput = new Input("mean",
37 | "Mean of exponential from which non-zero values are drawn in the"
38 | + " reverse jump.", Validate.REQUIRED);
39 |
40 | private RealParameter parameter;
41 | private double alpha;
42 |
43 | @Override
44 | public void initAndValidate() {
45 | parameter = parameterInput.get();
46 | alpha = alphaInput.get();
47 | }
48 |
49 | @Override
50 | public double proposal() {
51 |
52 | double logHR;
53 |
54 | // Select random element:
55 | int idx = Randomizer.nextInt(parameter.getDimension());
56 |
57 | double x = parameter.getValue(idx);
58 | if (x>0) {
59 | logHR = Math.log(Math.exp(-x/alpha)/alpha);
60 | x = 0.0;
61 | } else {
62 | x = Randomizer.nextExponential(1.0/alpha);
63 | logHR = -Math.log(Math.exp(-x/alpha)/alpha);
64 | }
65 |
66 | parameter.setValue(idx, x);
67 | return logHR;
68 | }
69 |
70 |
71 | public static void main(String[] args) {
72 |
73 | for (int i=0; i<100; i++) {
74 | System.out.println(Randomizer.nextExponential(10));
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/multitypetree/util/MAPTreeLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Tim Vaughan (tgvaughan@gmail.com)
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.inference.Distribution;
20 | import beast.base.core.Input;
21 | import beast.base.core.Input.Validate;
22 | import beast.base.evolution.tree.Tree;
23 | import multitypetree.evolution.tree.MigrationModel;
24 | import multitypetree.evolution.tree.MultiTypeTree;
25 |
26 | import java.io.PrintStream;
27 |
28 | /**
29 | * Used to log running estimate of MAP MultiTypeTree.
30 | *
31 | * @author Tim Vaughan (tgvaughan@gmail.com)
32 | */
33 | public class MAPTreeLogger extends Tree {
34 |
35 | public Input multiTypeTreeInput = new Input<>(
36 | "multiTypeTree",
37 | "Multi-type tree state to maximize posterior wrt.",
38 | Validate.REQUIRED);
39 |
40 | public Input posteriorInput = new Input<>(
41 | "posterior",
42 | "Posterior used to identify MAP tree",
43 | Validate.REQUIRED);
44 |
45 | MultiTypeTree currentMAPTree;
46 | double maxPosterior;
47 |
48 | @Override
49 | public void initAndValidate() {
50 | super.initAndValidate();
51 |
52 | currentMAPTree = multiTypeTreeInput.get().copy();
53 | currentMAPTree.setTypeTrait(multiTypeTreeInput.get().getTypeTrait());
54 | currentMAPTree.initAndValidate();
55 | maxPosterior = Double.NEGATIVE_INFINITY;
56 | }
57 |
58 | @Override
59 | public void init(PrintStream out) {
60 | currentMAPTree.init(out);
61 | }
62 |
63 | @Override
64 | public void log(long nSample, PrintStream out) {
65 | if (posteriorInput.get().getCurrentLogP()>maxPosterior) {
66 | maxPosterior = posteriorInput.get().getCurrentLogP();
67 | currentMAPTree.assignFrom(multiTypeTreeInput.get());
68 | }
69 | currentMAPTree.log(nSample, out);
70 | }
71 |
72 | @Override
73 | public void close(PrintStream out) {
74 | currentMAPTree.close(out);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/multitypetree/util/MigrationModelLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Tim Vaughan (tgvaughan@gmail.com)
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.core.BEASTObject;
20 | import beast.base.core.Input;
21 | import beast.base.core.Input.Validate;
22 | import multitypetree.evolution.tree.MultiTypeTree;
23 | import multitypetree.evolution.tree.SCMigrationModel;
24 | import multitypetree.evolution.tree.TypeSet;
25 | import beast.base.core.Loggable;
26 |
27 | import java.io.PrintStream;
28 |
29 | /**
30 | *
31 | * @author Tim Vaughan (tgvaughan@gmail.com)
32 | */
33 | public class MigrationModelLogger extends BEASTObject implements Loggable {
34 |
35 | public Input migModelInput = new Input<>("migrationModel",
36 | "Migration model to log.", Validate.REQUIRED);
37 |
38 | public Input multiTypeTreeInput = new Input<>(
39 | "multiTypeTree", "Tree from which to acquire type names.");
40 |
41 | private SCMigrationModel migModel;
42 | private MultiTypeTree mtTree;
43 |
44 | @Override
45 | public void initAndValidate() {
46 | migModel = migModelInput.get();
47 | mtTree = multiTypeTreeInput.get();
48 | }
49 |
50 | @Override
51 | public void init(PrintStream out) {
52 | String outName;
53 | TypeSet typeSet = migModel.getTypeSet();
54 |
55 | if (migModel.getID() == null || migModel.getID().matches("\\s*"))
56 | outName = "migModel";
57 | else
58 | outName = migModel.getID();
59 |
60 | out.print(outName + ".popSizeScaleFactor\t");
61 |
62 | for (int i=0; i
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.core.Input;
20 | import beast.base.core.Input.Validate;
21 | import beast.base.inference.Logger;
22 | import beast.base.inference.util.ESS;
23 | import beast.base.util.DiscreteStatistics;
24 | import multitypetree.evolution.tree.MultiTypeTree;
25 |
26 | import java.io.PrintStream;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | /**
31 | * Special logger for constructing unit tests on multi type tree operator
32 | * combinations.
33 | *
34 | * @author Tim Vaughan
35 | */
36 | public class MultiTypeTreeStatLogger extends Logger {
37 |
38 | public Input multiTypeTreeInput = new Input(
39 | "multiTypeTree",
40 | "Multi-type tree whose stats to log.",
41 | Validate.REQUIRED);
42 |
43 | public Input burninFracInput = new Input("burninFrac",
44 | "Fraction of trace to discard. Default 0.1.", 0.1);
45 |
46 | MultiTypeTree multiTypeTree;
47 | double burninFrac, logEvery;
48 |
49 | List heights = new ArrayList();
50 | double [] heightsArray;
51 | double heightMean, heightVar, heightESS;
52 |
53 | public MultiTypeTreeStatLogger () {
54 | loggersInput.setRule(Validate.OPTIONAL);
55 | }
56 |
57 | @Override
58 | public void initAndValidate() {
59 | multiTypeTree = multiTypeTreeInput.get();
60 | burninFrac = burninFracInput.get();
61 | logEvery = everyInput.get();
62 | };
63 |
64 | @Override
65 | public void init() {
66 | heights.clear();
67 | }
68 |
69 | @Override
70 | public void log(long nSample) {
71 |
72 | if ((nSample < 0) || (nSample % logEvery > 0))
73 | return;
74 |
75 | heights.add(multiTypeTree.getRoot().getHeight());
76 | }
77 |
78 | @Override
79 | public void close() {
80 | computeStatistics();
81 | }
82 |
83 | /**
84 | * Compute statistics from completed traces.
85 | */
86 | public void computeStatistics() {
87 |
88 | // Truncate burnin
89 | heights = heights.subList((int)(burninFrac*heights.size()),
90 | heights.size()-1);
91 |
92 | // Transfer to array for DiscreteStatistics methods:
93 | heightsArray = new double[heights.size()];
94 | for (int i=0; i
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Function;
21 | import beast.base.core.Input;
22 | import beast.base.core.Input.Validate;
23 | import beast.base.core.Loggable;
24 | import beast.base.evolution.tree.Node;
25 | import beast.base.inference.CalculationNode;
26 | import multitypetree.evolution.tree.MultiTypeNode;
27 | import multitypetree.evolution.tree.MultiTypeTree;
28 | import multitypetree.evolution.tree.SCMigrationModel;
29 |
30 | import java.io.PrintStream;
31 |
32 | /**
33 | * @author Tim Vaughan
34 | */
35 | @Description("Allows logging and defining distributions over number of"
36 | + " each node type on a multi-type tree.")
37 | public class NodeTypeCounts extends CalculationNode implements Function, Loggable {
38 |
39 | public Input multiTypeTreeInput = new Input<>(
40 | "multiTypeTree",
41 | "Multi-type tree whose changes will be counted.",
42 | Validate.REQUIRED);
43 |
44 | public Input migrationModelInput = new Input<>(
45 | "migrationModel",
46 | "Migration model needed to specify number of demes.",
47 | Validate.REQUIRED);
48 |
49 | public Input internalOnlyInput = new Input<>(
50 | "internalNodesOnly",
51 | "Only count types of internal nodes.",
52 | true);
53 |
54 | public Input useCacheInput = new Input<>(
55 | "useCache", "Cache counts, updating only when tree changes. "
56 | + "Warning: this will cause problems if this TypeChangeCounts "
57 | + "is not used in the target distribution.", false);
58 |
59 | private MultiTypeTree mtTree;
60 |
61 | private int nTypes;
62 |
63 | private int[] nodeTypeCounts;
64 | private boolean useCache, dirty;
65 |
66 | public NodeTypeCounts() { };
67 |
68 | @Override
69 | public void initAndValidate() {
70 | mtTree = multiTypeTreeInput.get();
71 | nTypes = migrationModelInput.get().getNTypes();
72 |
73 | nodeTypeCounts = new int[nTypes];
74 |
75 | useCache = useCacheInput.get();
76 | dirty = true;
77 | update();
78 | }
79 |
80 | /**
81 | * Update type change count array as necessary.
82 | */
83 | private void update() {
84 | if (!dirty)
85 | return;
86 |
87 | // Zero count array
88 | for (int i=0; i
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 |
21 | import java.io.PrintStream;
22 |
23 | import beast.base.inference.CalculationNode;
24 | import beast.base.core.Description;
25 | import beast.base.core.Function;
26 | import beast.base.core.Input;
27 | import beast.base.core.Loggable;
28 | import beast.base.core.Input.Validate;
29 | import beast.base.evolution.tree.Node;
30 | import beast.base.evolution.tree.Node;
31 | import beast.base.evolution.tree.Tree;
32 | import beast.base.evolution.tree.Tree;
33 |
34 |
35 | /**
36 | * @author Tim Vaughan
37 | */
38 | @Description("Logger to report total length of all branches on tree.")
39 | public class TreeLengthLogger extends CalculationNode implements Loggable, Function {
40 |
41 | public Input treeInput = new Input<>("tree",
42 | "Tree to report total branch length of.",
43 | Validate.REQUIRED);
44 |
45 | @Override
46 | public void initAndValidate() { }
47 |
48 | @Override
49 | public void init(PrintStream out) {
50 | Tree tree = treeInput.get();
51 | if (getID() == null || getID().matches("\\s*")) {
52 | out.print(tree.getID() + ".length\t");
53 | } else {
54 | out.print(getID() + "\t");
55 | }
56 | }
57 |
58 | @Override
59 | public void log(long nSample, PrintStream out) {
60 | Tree tree = treeInput.get();
61 | out.print(getSubTreeLength(tree.getRoot()) + "\t");
62 | }
63 |
64 | /**
65 | * Calculate total length of branches in sub-tree of node.
66 | *
67 | * @param node
68 | * @return total branch length
69 | */
70 | private double getSubTreeLength(Node node) {
71 | double length = 0;
72 | for (Node child : node.getChildren()) {
73 | length += node.getHeight()-child.getHeight();
74 | length += getSubTreeLength(child);
75 | }
76 |
77 | return length;
78 | }
79 |
80 | @Override
81 | public void close(PrintStream out) {
82 | }
83 |
84 | @Override
85 | public int getDimension() {
86 | return 1;
87 | }
88 |
89 | @Override
90 | public double getArrayValue() {
91 | return getSubTreeLength(treeInput.get().getRoot());
92 | }
93 |
94 | @Override
95 | public double getArrayValue(int iDim) {
96 | return getSubTreeLength(treeInput.get().getRoot());
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/multitypetree/util/TreeRootTypeLogger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.inference.CalculationNode;
20 | import beast.base.core.Description;
21 | import beast.base.core.Input;
22 | import beast.base.core.Function;
23 | import beast.base.core.Input.Validate;
24 | import multitypetree.evolution.tree.MultiTypeNode;
25 | import multitypetree.evolution.tree.MultiTypeTree;
26 | import beast.base.core.Loggable;
27 |
28 | import java.io.PrintStream;
29 |
30 |
31 | /**
32 | * @author Denise Kuehnert
33 | * Date: Feb 12, 2013
34 | * Time: 2:09:02 PM
35 | */
36 | @Description("Logger to report root type of a multi-type tree.")
37 | public class TreeRootTypeLogger extends CalculationNode implements Loggable, Function {
38 |
39 | public Input multiTypeTreeInput = new Input<>(
40 | "multiTypeTree", "MultiTypeTree to report root type of.", Validate.REQUIRED);
41 |
42 | public Input logStringTypesInput = new Input<>("logStringTypes",
43 | "Use string type labels in log. Warning: breaks tracer.", false);
44 |
45 | MultiTypeTree mtTree;
46 |
47 | @Override
48 | public void initAndValidate() {
49 | mtTree = multiTypeTreeInput.get();
50 | }
51 |
52 | @Override
53 | public void init(PrintStream out) {
54 |
55 | if (getID() == null || getID().matches("\\s*")) {
56 | out.print(mtTree.getID() + ".rootColor\t");
57 | } else {
58 | out.print(getID() + "\t");
59 | }
60 | }
61 |
62 | @Override
63 | public void log(long nSample, PrintStream out) {
64 | if (logStringTypesInput.get())
65 | out.print(mtTree.getTypeSet().getTypeName(((MultiTypeNode)mtTree.getRoot()).getNodeType()) + "\t");
66 | else
67 | out.print(((MultiTypeNode)mtTree.getRoot()).getNodeType() + "\t");
68 | }
69 |
70 | @Override
71 | public void close(PrintStream out) { };
72 |
73 | @Override
74 | public int getDimension() {
75 | return 1;
76 | }
77 |
78 | @Override
79 | public double getArrayValue() {
80 | return ((MultiTypeNode)mtTree.getRoot()).getNodeType();
81 | }
82 |
83 | @Override
84 | public double getArrayValue(int iDim) {
85 | return ((MultiTypeNode)mtTree.getRoot()).getNodeType();
86 | }
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/src/multitypetree/util/TypeChangeCounts.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.inference.CalculationNode;
20 | import beast.base.core.Description;
21 | import beast.base.core.Input;
22 | import beast.base.core.Input.Validate;
23 | import beast.base.core.Loggable;
24 | import beast.base.core.Function;
25 | import beast.base.evolution.tree.Node;
26 | import multitypetree.evolution.tree.MultiTypeNode;
27 | import multitypetree.evolution.tree.MultiTypeTree;
28 | import multitypetree.evolution.tree.SCMigrationModel;
29 |
30 | import java.io.PrintStream;
31 |
32 | /**
33 | * @author Tim Vaughan
34 | */
35 | @Description("Allows logging and defining distributions over number of"
36 | + " type changes on a multi-type tree.")
37 | public class TypeChangeCounts extends CalculationNode implements Function, Loggable {
38 |
39 | public Input multiTypeTreeInput = new Input<>(
40 | "multiTypeTree",
41 | "Multi-type tree whose changes will be counted.",
42 | Validate.REQUIRED);
43 |
44 | public Input migrationModelInput = new Input<>(
45 | "migrationModel",
46 | "Migration model needed to specify number of demes.",
47 | Validate.REQUIRED);
48 |
49 | public Input useCacheInput = new Input<>(
50 | "useCache", "Cache counts, updating only when tree changes. "
51 | + "Warning: this will cause problems if this TypeChangeCounts "
52 | + "is not used in the target distribution.", false);
53 |
54 | private MultiTypeTree mtTree;
55 |
56 | private int nTypes;
57 |
58 | private int[] typeChanges;
59 | private boolean useCache, dirty;
60 |
61 | public TypeChangeCounts() { };
62 |
63 | @Override
64 | public void initAndValidate() {
65 | mtTree = multiTypeTreeInput.get();
66 | nTypes = migrationModelInput.get().getNTypes();
67 |
68 | typeChanges = new int[nTypes*(nTypes-1)];
69 |
70 | useCache = useCacheInput.get();
71 | dirty = true;
72 | update();
73 | }
74 |
75 | /**
76 | * Update type change count array as necessary.
77 | */
78 | private void update() {
79 | if (!dirty)
80 | return;
81 |
82 | // Zero type change count array
83 | for (int i=0; ii)
119 | j -= 1;
120 | return i*(nTypes-1)+j;
121 | }
122 |
123 | @Override
124 | public int getDimension() {
125 | return nTypes*(nTypes-1);
126 | }
127 |
128 | @Override
129 | public double getArrayValue() {
130 | update();
131 | return typeChanges[0];
132 | }
133 |
134 | @Override
135 | public double getArrayValue(int iDim) {
136 | if (iDim
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.util;
18 |
19 | import beast.base.core.Description;
20 | import beast.base.core.Function;
21 | import beast.base.core.Input;
22 | import beast.base.core.Input.Validate;
23 | import beast.base.core.Loggable;
24 | import beast.base.evolution.tree.Node;
25 | import beast.base.inference.CalculationNode;
26 | import multitypetree.evolution.tree.MigrationModel;
27 | import multitypetree.evolution.tree.MultiTypeNode;
28 | import multitypetree.evolution.tree.MultiTypeTree;
29 | import multitypetree.evolution.tree.SCMigrationModel;
30 |
31 | import java.io.PrintStream;
32 |
33 | /**
34 | * @author Tim Vaughan
35 | */
36 | @Description("Allows logging and defining distributions over the lengths of"
37 | + " time lineages spend in each type on a multi-type tree.")
38 | public class TypeLengths extends CalculationNode implements Function, Loggable {
39 |
40 | public Input multiTypeTreeInput = new Input<>(
41 | "multiTypeTree",
42 | "Multi-type tree whose type-associated lengths will be recorded.",
43 | Validate.REQUIRED);
44 |
45 | public Input migrationModelInput = new Input<>(
46 | "migrationModel",
47 | "Migration model needed to specify number of demes.",
48 | Validate.REQUIRED);
49 |
50 | private MultiTypeTree mtTree;
51 | private MigrationModel migModel;
52 |
53 | private double[] typeLengths;
54 |
55 | public TypeLengths() { }
56 |
57 | @Override
58 | public void initAndValidate() {
59 | mtTree = multiTypeTreeInput.get();
60 | migModel = migrationModelInput.get();
61 |
62 | typeLengths = new double[migModel.getNTypes()];
63 |
64 | update();
65 | }
66 |
67 | /**
68 | * Update type change count array as necessary.
69 | */
70 | private void update() {
71 |
72 | // Zero type change count array
73 | for (int i=0; i
15 | */
16 | public class TypedNodeTreeLogger extends BEASTObject implements Loggable {
17 |
18 | public Input multiTypeTreeInput = new Input<>(
19 | "multiTypeTree",
20 | "Multi-type tree to log.",
21 | Input.Validate.REQUIRED);
22 |
23 | MultiTypeTree mtTree;
24 |
25 | @Override
26 | public void initAndValidate() {
27 | mtTree = multiTypeTreeInput.get();
28 | }
29 |
30 | @Override
31 | public void init(PrintStream out) {
32 | mtTree.init(out);
33 | }
34 |
35 | @Override
36 | public void log(long nSample, PrintStream out) {
37 |
38 | // Set up metadata string
39 | for (Node node : mtTree.getNodesAsArray()) {
40 | MultiTypeNode mtNode = (MultiTypeNode)node;
41 | mtNode.metaDataString = mtTree.getTypeLabel()
42 | + "=\""
43 | + mtTree.getTypeSet().getTypeName(mtNode.getNodeType())
44 | + "\"";
45 | }
46 |
47 | out.print("tree STATE_" + nSample + " = ");
48 | out.print(mtTree.getRoot().toSortedNewick(new int[1], true));
49 | out.print(";");
50 | }
51 |
52 | @Override
53 | public void close(PrintStream out) {
54 | mtTree.close(out);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/multitypetree/util/UtilMethods.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package multitypetree.util;
19 |
20 | import beast.base.inference.parameter.IntegerParameter;
21 | import multitypetree.evolution.tree.SCMigrationModel;
22 |
23 | /**
24 | *
25 | * @author Tim Vaughan
26 | */
27 | public class UtilMethods {
28 |
29 | public static double [] getSimulatedHeights(SCMigrationModel migrationModel,
30 | IntegerParameter leafTypes) throws Exception {
31 |
32 | // Generate ensemble:
33 | int reps = 100000;
34 | double[] heights = new double[reps];
35 |
36 | for (int i = 0; i < reps; i++) {
37 | multitypetree.evolution.tree.StructuredCoalescentMultiTypeTree sctree;
38 | sctree = new multitypetree.evolution.tree.StructuredCoalescentMultiTypeTree();
39 | sctree.initByName(
40 | "migrationModel", migrationModel,
41 | "leafTypes", leafTypes);
42 |
43 | heights[i] = sctree.getRoot().getHeight();
44 | }
45 |
46 | return heights;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test/multitypetree/coalescent/SCLikelihoodTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.coalescent;
18 |
19 | import org.junit.Test;
20 |
21 | import beast.base.inference.parameter.RealParameter;
22 | import junit.framework.TestCase;
23 | import multitypetree.distributions.StructuredCoalescentTreeDensity;
24 | import multitypetree.evolution.tree.MultiTypeTreeFromNewick;
25 | import multitypetree.evolution.tree.SCMigrationModel;
26 | import multitypetree.evolution.tree.TypeSet;
27 |
28 | /**
29 | * Tests for StructuredCoalescentLikelihood class methods.
30 | *
31 | * @author Tim Vaughan
32 | */
33 | public class SCLikelihoodTest extends TestCase {
34 |
35 | /**
36 | * Test of calculateLogP method, of class StructuredCoalescentLikelihood.
37 | */
38 | @Test
39 | public void testCalculateLogP() throws Exception {
40 | System.out.println("SCLikelihoodTest");
41 |
42 | // Assemble test MultiTypeTree:
43 | String newickStr =
44 | "(((A[&state=1]:0.25)[&state=0]:0.25,B[&state=0]:0.5)[&state=0]:1.5,"
45 | + "(C[&state=0]:1.0,D[&state=0]:1.0)[&state=0]:1.0)[&state=0]:0.0;";
46 |
47 | MultiTypeTreeFromNewick mtTree = new MultiTypeTreeFromNewick();
48 | mtTree.initByName(
49 | "value", newickStr,
50 | "typeLabel", "state");
51 |
52 | // Assemble migration model:
53 | RealParameter rateMatrix = new RealParameter();
54 | rateMatrix.initByName("value","2.0 1.0");
55 | RealParameter popSizes = new RealParameter();
56 | popSizes.initByName("value","5.0 10.0");
57 | SCMigrationModel migrationModel = new SCMigrationModel();
58 | migrationModel.initByName(
59 | "rateMatrix", rateMatrix,
60 | "popSizes", popSizes,
61 | "typeSet", new TypeSet("A", "B"));
62 |
63 | // Set up likelihood instance:
64 | StructuredCoalescentTreeDensity likelihood = new StructuredCoalescentTreeDensity();
65 | likelihood.initByName(
66 | "migrationModel", migrationModel,
67 | "multiTypeTree", mtTree);
68 |
69 | double expResult = -16.52831; // Calculated by hand
70 | double result = likelihood.calculateLogP();
71 |
72 | System.out.println(result);
73 | assertEquals(expResult, result, 1e-5);
74 |
75 |
76 |
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/test/multitypetree/operators/NSR_Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import multitypetree.distributions.StructuredCoalescentTreeDensity;
20 | import multitypetree.evolution.tree.MultiTypeTree;
21 | import multitypetree.evolution.tree.SCMigrationModel;
22 | import multitypetree.evolution.tree.StructuredCoalescentMultiTypeTree;
23 | import multitypetree.evolution.tree.TypeSet;
24 | import multitypetree.operators.NodeShiftRetype;
25 | import junit.framework.TestCase;
26 | import multitypetree.util.MultiTypeTreeStatLogger;
27 | import org.junit.Assert;
28 | import org.junit.Test;
29 |
30 | import beast.base.inference.MCMC;
31 | import beast.base.inference.Operator;
32 | import beast.base.inference.State;
33 | import beast.base.inference.parameter.RealParameter;
34 | import beast.base.util.Randomizer;
35 |
36 | /**
37 | *
38 | * @author Tim Vaughan
39 | */
40 | public class NSR_Test extends TestCase {
41 |
42 | @Test
43 | public void test() throws Exception {
44 | System.out.println("NSR test");
45 |
46 | // Fix seed.
47 | Randomizer.setSeed(42);
48 |
49 | // Assemble migration model:
50 | RealParameter rateMatrix = new RealParameter("0.1 0.1");
51 | RealParameter popSizes = new RealParameter("7.0 7.0");
52 | SCMigrationModel migModel = new SCMigrationModel();
53 | migModel.initByName(
54 | "rateMatrix", rateMatrix,
55 | "popSizes", popSizes,
56 | "typeSet", new TypeSet("A", "B"));
57 |
58 | // Assemble initial MultiTypeTree
59 | MultiTypeTree mtTree = new StructuredCoalescentMultiTypeTree();
60 | mtTree.initByName(
61 | "typeLabel", "deme",
62 | "migrationModel", migModel,
63 | "leafTypes","1 0");
64 |
65 | // Set up state:
66 | State state = new State();
67 | state.initByName("stateNode", mtTree);
68 |
69 | // Assemble distribution:
70 | StructuredCoalescentTreeDensity distribution =
71 | new StructuredCoalescentTreeDensity();
72 | distribution.initByName(
73 | "migrationModel", migModel,
74 | "multiTypeTree", mtTree);
75 |
76 | // Set up operators:
77 | Operator operatorNSR = new NodeShiftRetype();
78 | operatorNSR.initByName(
79 | "weight", 1.0,
80 | "multiTypeTree", mtTree,
81 | "migrationModel", migModel);
82 |
83 | // Set up stat analysis logger:
84 | MultiTypeTreeStatLogger logger = new MultiTypeTreeStatLogger();
85 | logger.initByName(
86 | "multiTypeTree", mtTree,
87 | "burninFrac", 0.1,
88 | "logEvery", 100);
89 |
90 | // Set up MCMC:
91 | MCMC mcmc = new MCMC();
92 | mcmc.initByName(
93 | "chainLength", "1000000",
94 | "state", state,
95 | "distribution", distribution,
96 | "operator", operatorNSR,
97 | "logger", logger);
98 |
99 | // Run MCMC:
100 | mcmc.run();
101 |
102 | System.out.format("height mean = %s\n", logger.getHeightMean());
103 | System.out.format("height var = %s\n", logger.getHeightVar());
104 | System.out.format("height ESS = %s\n", logger.getHeightESS());
105 |
106 | // Compare analysis results with truth:
107 | boolean withinTol = (logger.getHeightESS()>2000)
108 | && (Math.abs(logger.getHeightMean()-19.0)<0.5)
109 | && (Math.abs(logger.getHeightVar()-291)<30);
110 |
111 | Assert.assertTrue(withinTol);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/test/multitypetree/operators/STXR_NRR_MTU_TS_Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import multitypetree.distributions.StructuredCoalescentTreeDensity;
20 | import multitypetree.evolution.tree.MultiTypeTree;
21 | import multitypetree.evolution.tree.SCMigrationModel;
22 | import multitypetree.evolution.tree.StructuredCoalescentMultiTypeTree;
23 | import multitypetree.evolution.tree.TypeSet;
24 | import multitypetree.operators.MultiTypeTreeScale;
25 | import multitypetree.operators.MultiTypeUniform;
26 | import multitypetree.operators.NodeRetypeRandom;
27 | import multitypetree.operators.TypedSubtreeExchangeRandom;
28 | import junit.framework.TestCase;
29 | import multitypetree.util.MultiTypeTreeStatLogger;
30 | import org.junit.Assert;
31 | import org.junit.Test;
32 |
33 | import beast.base.inference.MCMC;
34 | import beast.base.inference.Operator;
35 | import beast.base.inference.State;
36 | import beast.base.inference.parameter.RealParameter;
37 | import beast.base.util.Randomizer;
38 |
39 | /**
40 | *
41 | * @author Tim Vaughan
42 | */
43 | public class STXR_NRR_MTU_TS_Test extends TestCase {
44 |
45 | @Test
46 | public void test() throws Exception {
47 | System.out.println("STXR_NRR_MTU_TS test");
48 |
49 | // Fix seed.
50 | Randomizer.setSeed(42);
51 |
52 | // Assemble migration model:
53 | RealParameter rateMatrix = new RealParameter("0.1 0.1");
54 | RealParameter popSizes = new RealParameter("7.0 7.0");
55 | SCMigrationModel migModel = new SCMigrationModel();
56 | migModel.initByName(
57 | "rateMatrix", rateMatrix,
58 | "popSizes", popSizes,
59 | "typeSet", new TypeSet("A", "B"));
60 |
61 | // Assemble initial MultiTypeTree
62 | MultiTypeTree mtTree = new StructuredCoalescentMultiTypeTree();
63 | mtTree.initByName(
64 | "typeLabel", "deme",
65 | "migrationModel", migModel,
66 | "leafTypes","1 1 0 0");
67 |
68 | // Set up state:
69 | State state = new State();
70 | state.initByName("stateNode", mtTree);
71 |
72 | // Assemble distribution:
73 | StructuredCoalescentTreeDensity distribution =
74 | new StructuredCoalescentTreeDensity();
75 | distribution.initByName(
76 | "migrationModel", migModel,
77 | "multiTypeTree", mtTree);
78 |
79 |
80 | // Set up operators:
81 | Operator operatorSTXR = new TypedSubtreeExchangeRandom();
82 | operatorSTXR.initByName(
83 | "weight", 1.0,
84 | "multiTypeTree", mtTree,
85 | "migrationModel", migModel,
86 | "mu", 0.2);
87 |
88 | Operator operatorNRR = new NodeRetypeRandom();
89 | operatorNRR.initByName(
90 | "weight", 1.0,
91 | "multiTypeTree", mtTree,
92 | "migrationModel", migModel,
93 | "mu", 0.2);
94 |
95 | Operator operatorMTU = new MultiTypeUniform();
96 | operatorMTU.initByName(
97 | "weight", 1.0,
98 | "multiTypeTree", mtTree,
99 | "migrationModel", migModel);
100 |
101 | Operator operatorMTTS = new MultiTypeTreeScale();
102 | operatorMTTS.initByName(
103 | "weight", 1.0,
104 | "multiTypeTree", mtTree,
105 | "migrationModel", migModel,
106 | "scaleFactor", 1.5,
107 | "useOldTreeScaler", false);
108 |
109 | // Set up stat analysis logger:
110 | MultiTypeTreeStatLogger logger = new MultiTypeTreeStatLogger();
111 | logger.initByName(
112 | "multiTypeTree", mtTree,
113 | "burninFrac", 0.1,
114 | "logEvery", 1000);
115 |
116 | // Set up MCMC:
117 | MCMC mcmc = new MCMC();
118 | mcmc.initByName(
119 | "chainLength", "10000000",
120 | "state", state,
121 | "distribution", distribution,
122 | "operator", operatorSTXR,
123 | "operator", operatorNRR,
124 | "operator", operatorMTU,
125 | "operator", operatorMTTS,
126 | "logger", logger);
127 |
128 | // Run MCMC:
129 | mcmc.run();
130 |
131 | System.out.format("height mean = %s\n", logger.getHeightMean());
132 | System.out.format("height var = %s\n", logger.getHeightVar());
133 | System.out.format("height ESS = %s\n", logger.getHeightESS());
134 |
135 | // Compare analysis results with truth:
136 | boolean withinTol = (logger.getHeightESS()>2000)
137 | && (Math.abs(logger.getHeightMean()-25.8)<0.5)
138 | && (Math.abs(logger.getHeightVar()-320)<30);
139 |
140 | Assert.assertTrue(withinTol);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/test/multitypetree/operators/STX_NR_MTU_TS_Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Tim Vaughan
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 | package multitypetree.operators;
18 |
19 | import multitypetree.util.UtilMethods;
20 | import multitypetree.distributions.StructuredCoalescentTreeDensity;
21 | import multitypetree.evolution.tree.MultiTypeTree;
22 | import multitypetree.evolution.tree.SCMigrationModel;
23 | import multitypetree.evolution.tree.StructuredCoalescentMultiTypeTree;
24 | import multitypetree.evolution.tree.TypeSet;
25 | import multitypetree.operators.MultiTypeTreeScale;
26 | import multitypetree.operators.MultiTypeUniform;
27 | import multitypetree.operators.NodeRetype;
28 | import multitypetree.operators.TypedSubtreeExchange;
29 | import junit.framework.TestCase;
30 | import multitypetree.util.MultiTypeTreeStatLogger;
31 | import org.junit.Assert;
32 | import org.junit.Test;
33 |
34 | import beast.base.inference.MCMC;
35 | import beast.base.inference.Operator;
36 | import beast.base.inference.State;
37 | import beast.base.inference.parameter.IntegerParameter;
38 | import beast.base.inference.parameter.RealParameter;
39 | import beast.base.util.DiscreteStatistics;
40 | import beast.base.util.Randomizer;
41 |
42 | /**
43 | *
44 | * @author Tim Vaughan
45 | */
46 | public class STX_NR_MTU_TS_Test extends TestCase {
47 |
48 | @Test
49 | public void test() throws Exception {
50 | System.out.println("STX_NR_MTU_TS test");
51 |
52 | // Test passing locally, not on Travis. WHY!?
53 |
54 | // Fix seed.
55 | Randomizer.setSeed(53);
56 |
57 | // Assemble migration model:
58 | RealParameter rateMatrix = new RealParameter("0.1 0.1");
59 | RealParameter popSizes = new RealParameter("7.0 7.0");
60 | SCMigrationModel migModel = new SCMigrationModel();
61 | migModel.initByName(
62 | "rateMatrix", rateMatrix,
63 | "popSizes", popSizes,
64 | "typeSet", new TypeSet("A", "B"));
65 |
66 | // Assemble initial MultiTypeTree
67 | MultiTypeTree mtTree = new StructuredCoalescentMultiTypeTree();
68 | mtTree.initByName(
69 | "typeLabel", "deme",
70 | "migrationModel", migModel,
71 | "leafTypes","1 1 0 0");
72 |
73 | // Set up state:
74 | State state = new State();
75 | state.initByName("stateNode", mtTree);
76 |
77 | // Assemble distribution:
78 | StructuredCoalescentTreeDensity distribution =
79 | new StructuredCoalescentTreeDensity();
80 | distribution.initByName(
81 | "migrationModel", migModel,
82 | "multiTypeTree", mtTree);
83 |
84 |
85 | // Set up operators:
86 | Operator operatorSTX = new TypedSubtreeExchange();
87 | operatorSTX.initByName(
88 | "weight", 1.0,
89 | "multiTypeTree", mtTree,
90 | "migrationModel", migModel);
91 |
92 | Operator operatorNR = new NodeRetype();
93 | operatorNR.initByName(
94 | "weight", 1.0,
95 | "multiTypeTree", mtTree,
96 | "migrationModel", migModel);
97 |
98 | Operator operatorMTU = new MultiTypeUniform();
99 | operatorMTU.initByName(
100 | "weight", 1.0,
101 | "migrationModel", migModel,
102 | "multiTypeTree", mtTree);
103 |
104 | Operator operatorMTTS = new MultiTypeTreeScale();
105 | operatorMTTS.initByName(
106 | "weight", 1.0,
107 | "multiTypeTree", mtTree,
108 | "migrationModel", migModel,
109 | "scaleFactor", 1.5,
110 | "useOldTreeScaler", false);
111 |
112 | // Set up stat analysis logger:
113 | MultiTypeTreeStatLogger logger = new MultiTypeTreeStatLogger();
114 | logger.initByName(
115 | "multiTypeTree", mtTree,
116 | "burninFrac", 0.1,
117 | "logEvery", 1000);
118 |
119 | // Set up MCMC:
120 | MCMC mcmc = new MCMC();
121 | mcmc.initByName(
122 | "chainLength", "1000000",
123 | "state", state,
124 | "distribution", distribution,
125 | "operator", operatorSTX,
126 | "operator", operatorNR,
127 | "operator", operatorMTU,
128 | "operator", operatorMTTS,
129 | "logger", logger);
130 |
131 | // Run MCMC:
132 | mcmc.run();
133 |
134 | System.out.format("height mean = %s\n", logger.getHeightMean());
135 | System.out.format("height var = %s\n", logger.getHeightVar());
136 | System.out.format("height ESS = %s\n", logger.getHeightESS());
137 |
138 | // Direct simulation:
139 | double [] heights = UtilMethods.getSimulatedHeights(migModel,
140 | new IntegerParameter("1 1 0 0"));
141 | double simHeightMean = DiscreteStatistics.mean(heights);
142 | double simHeightVar = DiscreteStatistics.variance(heights);
143 |
144 | System.out.format("sim height mean = %s\n", simHeightMean);
145 | System.out.format("sim height var = %s\n", simHeightVar);
146 |
147 | // Compare analysis results with truth:
148 | boolean withinTol = (logger.getHeightESS()>500)
149 | && (Math.abs(logger.getHeightMean()-simHeightMean)<2.0)
150 | && (Math.abs(logger.getHeightVar()-simHeightVar)<50);
151 |
152 | Assert.assertTrue(withinTol);
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/version.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------