Skip to content

Commit e4190ad

Browse files
committed
Update tests
1 parent 3dbdeab commit e4190ad

6 files changed

Lines changed: 43 additions & 96 deletions

File tree

NAMESPACE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ S3method(as.HPart,phylo)
4545
S3method(as.HPart_cpp,HPart_cpp)
4646
S3method(as.HPart_cpp,list)
4747
S3method(as.HPart_cpp,phylo)
48+
S3method(as.phylo,HPart_cpp)
4849
S3method(clone,HPart_cpp)
4950
S3method(median,multiPhylo)
5051
S3method(plot,HPart_cpp)
@@ -150,7 +151,6 @@ export(TreesConsistentWithTwoSplits)
150151
export(VisualizeMatching)
151152
export(as.HPart)
152153
export(as.HPart_cpp)
153-
export(as.phylo.HPart_cpp)
154154
export(clone)
155155
export(entropy_int)
156156
export(is.HPart)

R/hierarchical_mutual_information.R

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
#' @param tree1,tree2 Trees of class \code{phylo}, or lists of such trees.
2323
#' If \code{tree2} is not provided, distances will be calculated between
2424
#' each pair of trees in the list \code{tree1}.
25-
#' @param normalize Logical. If \code{TRUE}, normalize the result to range [0,1].
25+
#' @param normalize If `FALSE`, do not normalize the result. If a function,
26+
#' Normalize the result to range [0,1] by dividing by
27+
#' `Func(SelfHMI(tree1), SelfHMI(tree2))`, where `Func()` = `max()` if
28+
#' `normalize == TRUE`, `normalize()` otherwise.
2629
#' @param reportMatching Logical specifying whether to return the clade
2730
#' matchings as an attribute of the score.
2831
#'
@@ -58,7 +61,30 @@
5861
#' @family tree distances
5962
#' @export
6063
HierarchicalMutualInfo <- function(tree1, tree2 = NULL, normalize = FALSE) {
61-
UseMethod("HierarchicalMutualInfo")
64+
hp1 <- as.HPart_cpp(tree1)
65+
if (is.null(tree2)) {
66+
if (isFALSE(normalize)) {
67+
SelfHMI_cpp(hp1)
68+
} else {
69+
warning("Normalized self-information == 1; did you mean to provide tree2?")
70+
1
71+
}
72+
} else {
73+
hp2 <- as.HPart_cpp(tree2)
74+
hmi <- HMI_xptr(hp1, hp2)
75+
if (isFALSE(normalize)) {
76+
hmi
77+
} else {
78+
if (isTRUE(normalize)) {
79+
normalize <- max
80+
}
81+
if (!is.function(normalize)) {
82+
stop("`normalize` must be logical, or a function")
83+
}
84+
denom <- normalize(SelfHMI_cpp(hp1), SelfHMI_cpp(hp2))
85+
hmi / denom
86+
}
87+
}
6288
}
6389

6490
XLnX <- function(x) {

man/HierarchicalMutualInfo.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hmi.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ double hierarchical_self_info(const std::vector<TreeDist::HNode>& nodes, size_t
122122
double HMI_xptr(SEXP ptr1, SEXP ptr2) {
123123
Rcpp::XPtr<TreeDist::HPart> hp1(ptr1);
124124
Rcpp::XPtr<TreeDist::HPart> hp2(ptr2);
125+
if (hp1->nodes[hp1->root].n_tip != hp2->nodes[hp2->root].n_tip) {
126+
Rcpp::stop("Trees must have the same number of leaves");
127+
}
125128
return TreeDist::hierarchical_mutual_info(hp1->nodes, hp1->root,
126129
hp2->nodes, hp2->root).second;
127130
}

tests/testthat/Rplots.pdf

4.82 KB
Binary file not shown.
Lines changed: 7 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
library("TreeTools", quietly = TRUE)
2+
13
test_that("Hierarchical Mutual Information", {
2-
skip_if_not_installed("TreeTools")
3-
library("TreeTools", quietly = TRUE)
44

55
# Create test trees
66
tree1 <- BalancedTree(8)
@@ -38,97 +38,12 @@ test_that("Hierarchical Mutual Information", {
3838
expect_equal(hmi_self_norm, 1, tolerance = 1e-10)
3939

4040
# Test error handling
41-
expect_error(HierarchicalMutualInfo(tree1), "tree2 must be provided")
41+
expect_equal(HierarchicalMutualInfo(tree1), SelfHMI(tree1))
42+
expect_warning(expect_equal(HierarchicalMutualInfo(tree1, norm = TRUE), 1),
43+
"tree2")
4244

4345
# Test with different tip numbers (should error)
4446
tree_small <- BalancedTree(6)
45-
expect_error(HierarchicalMutualInfo(tree1, tree_small))
46-
47-
# Test reportMatching
48-
hmi_with_matching <- HierarchicalMutualInfo(tree1, tree2, reportMatching = TRUE)
49-
expect_true(is.numeric(hmi_with_matching))
50-
expect_true("matching" %in% names(attributes(hmi_with_matching)))
51-
52-
# Test expected value for bal6 vs pec6 (should be approximately 0.24)
53-
bal6 <- BalancedTree(6)
54-
pec6 <- PectinateTree(6)
55-
hmi_bal_pec <- HierarchicalMutualInfo(bal6, pec6)
56-
57-
# The expected value is 0.24 based on Python reference implementation
58-
expect_equal(hmi_bal_pec, 0.24, tolerance = 0.02)
59-
})
60-
61-
test_that("HMI helper functions", {
62-
skip_if_not_installed("TreeTools")
63-
library("TreeTools", quietly = TRUE)
64-
65-
tree <- BalancedTree(8)
66-
67-
# Test hierarchical partition building
68-
partition <- as.HPart(tree)
69-
70-
expect_true(is.list(partition))
71-
72-
# Test HMI recursive calculation
73-
tree2 <- PectinateTree(8)
74-
partition2 <- as.HPart(tree2)
75-
76-
result <- .CalculateHMIRecursive(partition, partition2)
77-
expect_true(is.list(result))
78-
expect_true("n_ts" %in% names(result))
79-
expect_true("I_ts" %in% names(result))
80-
expect_true(is.numeric(result$n_ts))
81-
expect_true(is.numeric(result$I_ts))
82-
expect_true(result$n_ts >= 0)
83-
expect_true(result$I_ts >= 0)
84-
})
85-
86-
test_that("HMI comparison with standard mutual information", {
87-
library("TreeTools", quietly = TRUE)
88-
89-
tree1 <- BalancedTree(8)
90-
tree2 <- PectinateTree(8)
91-
92-
# Compare HMI with some basic principles
93-
hmi <- HierarchicalMutualInfo(tree1, tree2)
94-
95-
# Both should be positive for different trees
96-
expect_true(hmi >= 0)
97-
98-
# Test with identical trees
99-
hmi_identical <- HierarchicalMutualInfo(tree1, tree1)
100-
101-
expect_true(hmi_identical >= 0)
102-
expect_true(is.numeric(hmi))
103-
expect_true(is.numeric(hmi_identical))
104-
})
105-
106-
test_that("HMI with list inputs", {
107-
library("TreeTools", quietly = TRUE)
108-
109-
trees <- list(
110-
BalancedTree(8),
111-
PectinateTree(8),
112-
RandomTree(8, 1)
113-
)
114-
115-
# Test with list input
116-
hmi_result <- HierarchicalMutualInfo(trees)
117-
118-
expect_true(inherits(hmi_result, "dist"))
119-
expect_equal(length(hmi_result), 3) # 3 pairwise distances for 3 trees
120-
121-
# Convert to full matrix to test properties
122-
hmi_matrix <- as.matrix(hmi_result)
123-
expect_equal(dim(hmi_matrix), c(3, 3))
124-
125-
# Matrix should be symmetric
126-
expect_equal(hmi_matrix[1, 2], hmi_matrix[2, 1], tolerance = 1e-10)
127-
expect_equal(hmi_matrix[1, 3], hmi_matrix[3, 1], tolerance = 1e-10)
128-
expect_equal(hmi_matrix[2, 3], hmi_matrix[3, 2], tolerance = 1e-10)
129-
130-
# Diagonal should be zero (distance from tree to itself in distance matrix)
131-
expect_equal(hmi_matrix[1, 1], 0, tolerance = 1e-10)
132-
expect_equal(hmi_matrix[2, 2], 0, tolerance = 1e-10)
133-
expect_equal(hmi_matrix[3, 3], 0, tolerance = 1e-10)
47+
expect_error(HierarchicalMutualInfo(tree1, tree_small),
48+
"number of leaves")
13449
})

0 commit comments

Comments
 (0)