File size: 1,559 Bytes
81ae663
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Exact graph statistics and candidate-level molecular measurements."""

import numpy as np
from .exact import endpoint_distribution, expected_cost, solve


def graph_metrics(graph, forward, log_rewards, temperature):
    """Return exact endpoint TV, joint KL and mean cost on the stored DAG."""
    ref = solve(graph, log_rewards, temperature)
    p = endpoint_distribution(graph, forward)
    mass = np.zeros(len(graph.nodes))
    mass[graph.root_index] = 1.0
    joint_kl = 0.0
    for u in graph.order:
        for i in graph.outgoing[u]:
            f = mass[u] * forward[i]
            if f > 0:
                joint_kl += f * np.log(forward[i] / ref.forward[i])
            mass[graph.node_index[graph.edges[i].target]] += f
    endpoint_kl = sum(p[y] * np.log(p[y] / ref.target[y]) for y in p if p[y] > 0)
    return {
        "endpoint_tv": 0.5 * sum(abs(p[y] - ref.target[y]) for y in p),
        "joint_kl": float(joint_kl),
        "conditional_kl": max(0.0, float(joint_kl - endpoint_kl)),
        "mean_cost": expected_cost(graph, forward),
        "conditional_free_energy_gap": temperature
        * max(0.0, float(joint_kl - endpoint_kl)),
    }


def hypervolume_2d(points):
    """Dominated area for utility points clipped to [0,1]^2, reference (0,0)."""
    a = np.clip(np.asarray(points, dtype=float), 0, 1)
    if a.size == 0:
        return 0.0
    a = a[np.argsort(-a[:, 0])]
    area = 0.0
    height = 0.0
    for x, y in a:
        if y > height:
            area += x * (y - height)
            height = y
    return float(area)