Skip to article frontmatterSkip to article content

Exercises

The aim of these exercises is for you to derive simple functions based on phylo2vec definitions and functions we saw in the tutorial. You will also learn how to test the validity and benchmark the efficiency of your implementations using pytest and pytest-benchmark, respectively.

Imports

import os

import numpy as np
import phylo2vec as p2v

os.chdir("../")

bench_dir = "src/benchmarks"
test_dir = "src/tests"

Testing with pytest

The pytest framework makes it easy to write small, readable tests for Python applications and libraries.

We have already added the package to our repository via pixi add pytest.

To write a test, create a python file starting with test_. Define test functions starting with test_.

See the example below of tests/test_example.py:

from IPython.display import Markdown

# Read the file and display in markdown
with open(f'{test_dir}/test_example.py', 'r') as f:
    benchmark_content = f.read()

Markdown(
f"""
```python
{benchmark_content}
```
"""
)
Loading...

To run tests, simply run:

!pixi run pytest $test_dir -v
 activating environment                                                        ============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-8.4.2, pluggy-1.6.0 -- /workspaces/phylo2vec-workshop/.pixi/envs/default/bin/python3.11
cachedir: .pytest_cache
benchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /workspaces/phylo2vec-workshop
plugins: benchmark-5.1.0, anyio-4.10.0
collected 47 items                                                             

src/tests/test_example.py::test_fibonacci PASSED                         [  2%]
src/tests/test_example.py::test_fail_fibonacci FAILED                    [  4%]
src/tests/test_example.py::test_from_and_to_newick[5] PASSED             [  6%]
src/tests/test_example.py::test_from_and_to_newick[6] PASSED             [  8%]
src/tests/test_example.py::test_from_and_to_newick[7] PASSED             [ 10%]
src/tests/test_example.py::test_from_and_to_newick[8] PASSED             [ 12%]
src/tests/test_example.py::test_from_and_to_newick[9] PASSED             [ 14%]
src/tests/test_example.py::test_from_and_to_newick[10] PASSED            [ 17%]
src/tests/test_example.py::test_from_and_to_newick[11] PASSED            [ 19%]
src/tests/test_example.py::test_from_and_to_newick[12] PASSED            [ 21%]
src/tests/test_example.py::test_from_and_to_newick[13] PASSED            [ 23%]
src/tests/test_example.py::test_from_and_to_newick[14] PASSED            [ 25%]
src/tests/test_example.py::test_from_and_to_newick[15] PASSED            [ 27%]
src/tests/test_example.py::test_from_and_to_newick[16] PASSED            [ 29%]
src/tests/test_example.py::test_from_and_to_newick[17] PASSED            [ 31%]
src/tests/test_example.py::test_from_and_to_newick[18] PASSED            [ 34%]
src/tests/test_example.py::test_from_and_to_newick[19] PASSED            [ 36%]
src/tests/test_example.py::test_from_and_to_newick[20] PASSED            [ 38%]
src/tests/test_example.py::test_from_and_to_newick[21] PASSED            [ 40%]
src/tests/test_example.py::test_from_and_to_newick[22] PASSED            [ 42%]
src/tests/test_example.py::test_from_and_to_newick[23] PASSED            [ 44%]
src/tests/test_example.py::test_from_and_to_newick[24] PASSED            [ 46%]
src/tests/test_example.py::test_from_and_to_newick[25] PASSED            [ 48%]
src/tests/test_example.py::test_from_and_to_newick[26] PASSED            [ 51%]
src/tests/test_example.py::test_from_and_to_newick[27] PASSED            [ 53%]
src/tests/test_example.py::test_from_and_to_newick[28] PASSED            [ 55%]
src/tests/test_example.py::test_from_and_to_newick[29] PASSED            [ 57%]
src/tests/test_example.py::test_from_and_to_newick[30] PASSED            [ 59%]
src/tests/test_example.py::test_from_and_to_newick[31] PASSED            [ 61%]
src/tests/test_example.py::test_from_and_to_newick[32] PASSED            [ 63%]
src/tests/test_example.py::test_from_and_to_newick[33] PASSED            [ 65%]
src/tests/test_example.py::test_from_and_to_newick[34] PASSED            [ 68%]
src/tests/test_example.py::test_from_and_to_newick[35] PASSED            [ 70%]
src/tests/test_example.py::test_from_and_to_newick[36] PASSED            [ 72%]
src/tests/test_example.py::test_from_and_to_newick[37] PASSED            [ 74%]
src/tests/test_example.py::test_from_and_to_newick[38] PASSED            [ 76%]
src/tests/test_example.py::test_from_and_to_newick[39] PASSED            [ 78%]
src/tests/test_example.py::test_from_and_to_newick[40] PASSED            [ 80%]
src/tests/test_example.py::test_from_and_to_newick[41] PASSED            [ 82%]
src/tests/test_example.py::test_from_and_to_newick[42] PASSED            [ 85%]
src/tests/test_example.py::test_from_and_to_newick[43] PASSED            [ 87%]
src/tests/test_example.py::test_from_and_to_newick[44] PASSED            [ 89%]
src/tests/test_example.py::test_from_and_to_newick[45] PASSED            [ 91%]
src/tests/test_example.py::test_from_and_to_newick[46] PASSED            [ 93%]
src/tests/test_example.py::test_from_and_to_newick[47] PASSED            [ 95%]
src/tests/test_example.py::test_from_and_to_newick[48] PASSED            [ 97%]
src/tests/test_example.py::test_from_and_to_newick[49] PASSED            [100%]

=================================== FAILURES ===================================
_____________________________ test_fail_fibonacci ______________________________

    def test_fail_fibonacci():
>       assert fibonacci(10) == 54  # This test is expected to fail
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
E       assert 55 == 54
E        +  where 55 = fibonacci(10)

src/tests/test_example.py:17: AssertionError
=============================== warnings summary ===============================
.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44
  /workspaces/phylo2vec-workshop/.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
    import cgi

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED src/tests/test_example.py::test_fail_fibonacci - assert 55 == 54
=================== 1 failed, 46 passed, 1 warning in 0.27s ====================

pytest automatically discovers files and functions starting with test_. It will show a summary of passed and failed tests.

The -v option is optional, but helps visualizing which tests passed/failed.

Benchmarking with pytest-benchmark

The pytest-benchmark is a package that integrates with pytest to measure and report performance of your code. It uses a similar syntax as pytest tests.

We have already added the package to our repository via pixi add pytest-benchmark.

To write a test, create a python file starting with test_. Define test functions starting with test_.

See the example below of src/benchmarks/test_bench.py:

# Read the file and display in markdown
with open(f"{bench_dir}/test_bench.py", "r") as f:
    benchmark_content = f.read()

Markdown(
    f"""
```python
{benchmark_content}
```
"""
)
Loading...

To run a benchmark, you can simply run:

!pixi run pytest $bench_dir
 activating environment                                                        ============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-8.4.2, pluggy-1.6.0
benchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /workspaces/phylo2vec-workshop
plugins: benchmark-5.1.0, anyio-4.10.0
collected 18 items                                                             

src/benchmarks/test_bench.py ..................                          [100%]

=============================== warnings summary ===============================
.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44
  /workspaces/phylo2vec-workshop/.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
    import cgi

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

---------------------------------------------------------------------------------------------------- benchmark: 18 tests ----------------------------------------------------------------------------------------------------
Name (time in ns)                       Min                     Max                   Mean                StdDev                 Median                 IQR              Outliers  OPS (Kops/s)            Rounds  Iterations
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fibonacci[200]                382.2500 (1.0)        9,908.5000 (3.95)        433.4687 (1.0)        110.3238 (1.88)        402.3000 (1.0)        9.5000 (1.27)    10189;12944    2,306.9718 (1.0)      112778          20
test_fibonacci[300]                389.7000 (1.02)      22,234.4500 (8.87)        435.9270 (1.01)       117.3388 (2.00)        409.2500 (1.02)       9.0000 (1.20)     8525;11109    2,293.9620 (0.99)     111645          20
test_fibonacci[400]                412.2500 (1.08)      73,262.0500 (29.24)       477.7996 (1.10)       254.8987 (4.35)        430.8000 (1.07)       9.9999 (1.33)     6723;17333    2,092.9274 (0.91)     107666          20
test_fibonacci[500]                422.3000 (1.10)       2,505.6500 (1.0)         448.9827 (1.04)        58.5759 (1.0)         438.8500 (1.09)       7.5000 (1.0)       3766;5593    2,227.2574 (0.97)     107666          20
test_fibonacci[600]                433.8000 (1.13)       3,382.9500 (1.35)        484.9448 (1.12)       110.8138 (1.89)        451.8500 (1.12)       9.0000 (1.20)     9742;12439    2,062.0903 (0.89)     104954          20
test_fibonacci[100]                439.9999 (1.15)      43,991.9995 (17.56)       508.4703 (1.17)       369.6834 (6.31)        461.0001 (1.15)      21.0002 (2.80)     3386;10442    1,966.6832 (0.85)     126040           1
test_fibonacci[700]                453.3500 (1.19)       2,786.7000 (1.11)        501.1224 (1.16)       103.8136 (1.77)        471.3500 (1.17)       8.5500 (1.14)     8655;11284    1,995.5203 (0.86)     101236          20
test_fibonacci[800]                465.8500 (1.22)      15,560.5500 (6.21)        530.3421 (1.22)       138.9651 (2.37)        485.4000 (1.21)       9.5000 (1.27)    13520;16030    1,885.5754 (0.82)      99911          20
test_fibonacci[900]                531.0003 (1.39)      48,119.9995 (19.20)       702.6036 (1.62)       506.6704 (8.65)        572.0003 (1.42)      60.0003 (8.00)     4385;26263    1,423.2776 (0.62)     119977           1
test_p2v_sample_vector[100]      5,769.9999 (15.09)     51,265.9999 (20.46)     7,273.0330 (16.78)    2,350.3239 (40.12)     6,301.9997 (15.66)    290.0006 (38.67)     2168;2451      137.4942 (0.06)      11139           1
test_p2v_sample_vector[200]     11,271.0004 (29.49)     54,582.0003 (21.78)    13,192.1766 (30.43)    3,108.3485 (53.07)    12,033.0005 (29.91)    341.0005 (45.47)     4294;5496       75.8025 (0.03)      32157           1
test_p2v_sample_vector[300]     17,441.9993 (45.63)     56,545.9995 (22.57)    19,134.5051 (44.14)    3,070.7591 (52.42)    18,334.0007 (45.57)    381.0001 (50.80)     1082;1735       52.2616 (0.02)      16434           1
test_p2v_sample_vector[400]     23,644.0001 (61.85)     64,298.9999 (25.66)    25,554.7083 (58.95)    3,401.3163 (58.07)    24,725.9995 (61.46)    450.0007 (60.00)     1270;2012       39.1317 (0.02)      21023           1
test_p2v_sample_vector[500]     29,525.0002 (77.24)     79,417.9996 (31.70)    31,320.9925 (72.26)    3,499.1136 (59.74)    30,526.0000 (75.88)    512.0010 (68.27)      811;1258       31.9275 (0.01)      14610           1
test_p2v_sample_vector[600]     35,746.9999 (93.52)     83,648.9999 (33.38)    37,774.1198 (87.14)    3,312.6795 (56.55)    36,988.9995 (91.94)    610.9995 (81.47)     1200;1682       26.4732 (0.01)      19598           1
test_p2v_sample_vector[700]     41,817.9998 (109.40)   111,127.0003 (44.35)    45,535.0322 (105.05)   6,993.2364 (119.39)   43,400.9999 (107.88)   900.9998 (120.13)    1420;2292       21.9611 (0.01)      18251           1
test_p2v_sample_vector[800]     47,708.9998 (124.81)   125,945.0000 (50.26)    51,593.4772 (119.02)   7,911.5503 (135.06)   49,151.0000 (122.17)   841.0007 (112.13)    1147;2042       19.3823 (0.01)      15889           1
test_p2v_sample_vector[900]     53,167.9998 (139.09)   114,212.9995 (45.58)    55,896.6661 (128.95)   4,774.5360 (81.51)    54,782.9995 (136.17)   791.0003 (105.47)    1053;1319       17.8902 (0.01)      14009           1
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
======================== 18 passed, 1 warning in 15.14s ========================

To save results, you can use the --benchmark-autosave option

!pixi run pytest $bench_dir --benchmark-autosave
 activating environment                                                        ============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-8.4.2, pluggy-1.6.0
benchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /workspaces/phylo2vec-workshop
plugins: benchmark-5.1.0, anyio-4.10.0
collected 18 items                                                             

src/benchmarks/test_bench.py ..................                          [100%]
Saved benchmark data in: /workspaces/phylo2vec-workshop/.benchmarks/Linux-CPython-3.11-64bit/0002_c5d0e011fb6e64de7b82770013bbea31d824a8e9_20250916_214206_uncommited-changes.json


=============================== warnings summary ===============================
.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44
  /workspaces/phylo2vec-workshop/.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
    import cgi

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

---------------------------------------------------------------------------------------------------- benchmark: 18 tests -----------------------------------------------------------------------------------------------------
Name (time in ns)                       Min                     Max                   Mean                StdDev                 Median                   IQR             Outliers  OPS (Kops/s)            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fibonacci[200]                383.2000 (1.0)        5,487.7500 (2.39)        434.4212 (1.0)        107.5064 (1.31)        402.7500 (1.0)          9.5500 (1.19)   11337;14001    2,301.9134 (1.0)      118822          20
test_fibonacci[300]                389.7500 (1.02)       3,060.2000 (1.34)        449.2870 (1.03)       119.7369 (1.46)        409.2500 (1.02)         9.5000 (1.19)   13700;16135    2,225.7490 (0.97)     118977          20
test_fibonacci[400]                409.7500 (1.07)       2,715.1000 (1.18)        468.8582 (1.08)       119.4249 (1.46)        428.3000 (1.06)         9.0000 (1.12)   13061;15452    2,132.8411 (0.93)     108850          20
test_fibonacci[600]                433.3000 (1.13)       3,652.3000 (1.59)        469.5002 (1.08)        81.8914 (1.0)         451.8500 (1.12)         8.0500 (1.01)     5466;7642    2,129.9246 (0.93)     106417          20
test_fibonacci[100]                439.9999 (1.15)      99,676.0000 (43.49)       524.8717 (1.21)       473.2371 (5.78)        471.0000 (1.17)        29.9997 (3.75)     2976;9641    1,905.2275 (0.83)     118695           1
test_fibonacci[700]                455.8500 (1.19)     106,743.5000 (46.57)       558.4633 (1.29)       442.0954 (5.40)        474.3500 (1.18)       117.7000 (14.71)    815;15726    1,790.6280 (0.78)     100919          20
test_fibonacci[800]                465.3500 (1.21)       2,291.9000 (1.0)         501.4572 (1.15)        85.8540 (1.05)        482.9000 (1.20)         8.0000 (1.0)      3620;5271    1,994.1883 (0.87)      72015          20
test_fibonacci[900]                475.4000 (1.24)       2,339.3500 (1.02)        518.7727 (1.19)        98.3800 (1.20)        493.9000 (1.23)         8.5000 (1.06)     6677;8913    1,927.6265 (0.84)      96442          20
test_fibonacci[500]                489.9994 (1.28)      52,227.0002 (22.79)       750.7442 (1.73)       555.9586 (6.79)        570.9999 (1.42)       421.0005 (52.63)     2573;679    1,332.0116 (0.58)      73497           1
test_p2v_sample_vector[100]      5,881.0001 (15.35)     49,983.0003 (21.81)     7,571.1856 (17.43)    2,467.1965 (30.13)     6,391.9997 (15.87)    1,354.5000 (169.31)   3042;3155      132.0797 (0.06)      13337           1
test_p2v_sample_vector[200]     11,481.9995 (29.96)     45,244.9995 (19.74)    14,078.5847 (32.41)    3,883.9567 (47.43)    12,202.9996 (30.30)      811.9996 (101.50)   5799;6193       71.0299 (0.03)      27573           1
test_p2v_sample_vector[300]     17,692.9998 (46.17)     60,022.0001 (26.19)    19,240.9226 (44.29)    2,658.5263 (32.46)    18,624.9999 (46.24)      371.9997 (46.50)    1924;3546       51.9726 (0.02)      36750           1
test_p2v_sample_vector[400]     24,144.9998 (63.01)     68,907.9998 (30.07)    27,009.2678 (62.17)    5,178.9016 (63.24)    25,187.0006 (62.54)      570.0003 (71.25)    2159;2712       37.0243 (0.02)      18869           1
test_p2v_sample_vector[500]     29,836.0001 (77.86)     81,041.0002 (35.36)    32,351.1328 (74.47)    4,642.7613 (56.69)    31,038.0001 (77.07)      580.0002 (72.50)    1843;2441       30.9108 (0.01)      22763           1
test_p2v_sample_vector[600]     36,327.9996 (94.80)    779,402.9998 (340.07)   39,409.7790 (90.72)    8,083.2200 (98.71)    37,649.9993 (93.48)      682.0001 (85.25)    1154;2047       25.3744 (0.01)      18766           1
test_p2v_sample_vector[700]     42,167.9997 (110.04)   107,921.0006 (47.09)    46,003.2612 (105.90)   6,519.6108 (79.61)    44,092.9998 (109.48)     801.0002 (100.12)   1159;1913       21.7376 (0.01)      15976           1
test_p2v_sample_vector[800]     48,660.9997 (126.99)   109,102.9999 (47.60)    52,922.3153 (121.82)   8,304.0366 (101.40)   50,402.9999 (125.15)     992.4997 (124.06)   1116;1942       18.8956 (0.01)      15356           1
test_p2v_sample_vector[900]     54,280.9994 (141.65)   129,662.0003 (56.57)    57,057.8936 (131.34)   4,878.0978 (59.57)    55,884.0002 (138.76)     803.0001 (100.37)     730;922       17.5261 (0.01)       9451           1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
======================== 18 passed, 1 warning in 16.50s ========================

A file will appear in the .benchmarks directory with the result of your benchmark. There are several options for plotting the benchmark results, we show here one with seaborn and pandas. Here is an example script:

import json

from pathlib import Path

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

dfs = []

for benchmark_file in Path(".benchmarks").rglob("*.json"):
    # Load the benchmark data
    with open(benchmark_file, "r") as f:
        data_i = json.load(f)

    df_i = pd.DataFrame(data_i["benchmarks"])

    df_i["param"] = df_i.param.astype(int)

    df_i["name"] = df_i["name"].apply(lambda x: x.replace("test_", "").split("[")[0])

    df_i = pd.concat(
        [df_i.drop("stats", axis=1), pd.json_normalize(df_i["stats"])], axis=1
    )

    df_i["cpu_time"] = df_i["mean"]
    df_i["cpu_stddev"] = df_i["stddev"]

    df_i["run"] = df_i["name"] + f"_{Path(benchmark_file).stem.split('_')[0]}"

    dfs.append(df_i)

df = pd.concat(dfs, axis=0).reset_index(drop=True).query("run.str.contains('sample')")

sns.pointplot(
    x="param",
    y="cpu_time",
    hue="run",
    palette="Blues",
    linestyles=None,
    data=df,
    markersize=3,
    linewidth=1.25,
)
plt.ylabel("Time (s)")
plt.xlabel("Number of leaves")
plt.show()
<Figure size 640x480 with 1 Axes>

Exercise 1: Adjacency matrix with phylo2vec

The goal of this exercise is to create an adjacency matrix using phylo2vec.

An adjacency matrix can be used to represent any graph (and thus, any tree). It is a square matrix AA such that each element AijA_{ij} is 1 when there is an edge from a node ii to node jj, and 0 when there is no edge.

As a phylo2vec vector vv represents a rooted binary tree, it represents a directed graph. Thus, each edge goes from a parent to a child, but not vice versa.

To check that your function works, write a test file called test_adjacency.py in the tests directory, and run pytest to check that you pass all tests!

Example inputs and outputs:

# Example 0
v0 = np.array([0, 2])
a0 = np.array([[0, 0, 0, 1, 0],
       [0, 0, 0, 1, 0],
       [0, 0, 0, 0, 1],
       [0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0]])
# Example 1
v1 = np.array([0, 0, 0])
a1 = np.array([[0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 0]])
# Example 2
v2 = np.array([0, 1, 0])
a2 = np.array([[0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 0]])
# Example 3
v3 = np.array([0, 1, 2, 3, 4])
a3 = np.array(
      [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
#################################################
############# YOUR CODE STARTS HERE #############
#################################################

def adjacency_matrix(v: np.ndarray) -> np.ndarray:
    """Create the adjacency matrix of the tree represented by a phylo2vec vector.

    Parameters
    ----------
    v: np.ndarray
        A phylo2vec vector.

    Returns
    -------
    np.ndarray
        The adjacency matrix of the tree represented by the vector.
    """
    raise NotImplementedError

#################################################
############## YOUR CODE ENDS HERE ##############

Exercise 2: Visualising trees with phylo2vec

The goal of this exercise is to plot trees using phylo2vec. You are free to decide:

  • the language to use (Rust, R, Python, ...)
  • the output format (ASCII, image, interactive visualisation etc.)
  • the dependencies that you may need.

Ideally, we would like to minimize dependencies, but plotting libraries might be necessary to render nice phylogenetic trees!

Use pytest-benchmark to evaluate the efficiency of your solution.

#################################################
############# YOUR CODE STARTS HERE #############
#################################################


def visualize_tree(v: np.ndarray):
    """Visualize the tree represented by a phylo2vec vector.

    Parameters
    ----------
    v: np.ndarray
        A phylo2vec vector.
    """
    # You may also try to plot a tree with branch lengths using the phylo2vec matrix format
    raise NotImplementedError


#################################################
############## YOUR CODE ENDS HERE ##############