File size: 3,745 Bytes
19abe39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
Validates all .fold target files against origami theorems.
Run directly: python -m env.targets.validator
"""
import json
import os
import sys
from pathlib import Path

from ..graph import CreaseGraph
from ..verifier import check_kawasaki_at_vertex, check_maekawa_at_vertex, check_blb_at_vertex


def build_graph_from_fold(fold_data: dict) -> CreaseGraph:
    """
    Reconstruct a CreaseGraph from a FOLD JSON dict.
    Used to validate target files.
    """
    graph = CreaseGraph()

    verts = fold_data['vertices_coords']
    edges = fold_data['edges_vertices']
    assignments = fold_data['edges_assignment']

    # Map file vertex indices to graph vertex IDs
    vert_map = {}
    for i, (x, y) in enumerate(verts):
        vid = graph.add_vertex(float(x), float(y))
        vert_map[i] = vid

    # Add edges (boundary edges from init may already exist, add_edge handles dedup)
    for i, (v1_idx, v2_idx) in enumerate(edges):
        v1_id = vert_map[v1_idx]
        v2_id = vert_map[v2_idx]
        assignment = assignments[i]
        graph.add_edge(v1_id, v2_id, assignment)

    return graph


def validate_target(fold_path: str) -> dict:
    """
    Validate a single .fold target file.
    Returns {'file': str, 'valid': bool, 'issues': list[str], 'interior_vertices': int}
    """
    with open(fold_path) as f:
        fold_data = json.load(f)

    issues = []

    # Basic structure checks
    required = ['vertices_coords', 'edges_vertices', 'edges_assignment', 'edges_foldAngle']
    for field in required:
        if field not in fold_data:
            issues.append(f"Missing field: {field}")

    if issues:
        return {'file': os.path.basename(fold_path), 'valid': False, 'issues': issues, 'interior_vertices': -1}

    n_edges = len(fold_data['edges_vertices'])
    if len(fold_data['edges_assignment']) != n_edges:
        issues.append("edges_assignment length mismatch")
    if len(fold_data['edges_foldAngle']) != n_edges:
        issues.append("edges_foldAngle length mismatch")

    # Build graph and check theorems
    graph = build_graph_from_fold(fold_data)
    interior = graph.interior_vertices()

    for v_id in interior:
        ok, alt_sum = check_kawasaki_at_vertex(v_id, graph)
        if not ok:
            issues.append(f"Kawasaki violated at vertex {v_id} (alt_sum={alt_sum:.6f})")

        if not check_maekawa_at_vertex(v_id, graph):
            issues.append(f"Maekawa violated at vertex {v_id}")

        blb_violations = check_blb_at_vertex(v_id, graph)
        if blb_violations:
            issues.append(f"BLB violated at vertex {v_id}: {blb_violations}")

    return {
        'file': os.path.basename(fold_path),
        'valid': len(issues) == 0,
        'issues': issues,
        'interior_vertices': len(interior),
    }


def validate_all(targets_dir: str = None) -> bool:
    """Validate all .fold files in the targets directory. Returns True if all pass."""
    if targets_dir is None:
        targets_dir = Path(__file__).parent

    all_pass = True
    fold_files = sorted(Path(targets_dir).glob('*.fold'))

    if not fold_files:
        print("No .fold files found")
        return False

    for fold_path in fold_files:
        result = validate_target(str(fold_path))
        status = "OK" if result['valid'] else "FAIL"
        n_interior = result['interior_vertices']
        print(f"  [{status}] {result['file']}{n_interior} interior vertices")
        if result['issues']:
            for issue in result['issues']:
                print(f"         ! {issue}")
        if not result['valid']:
            all_pass = False

    return all_pass


if __name__ == '__main__':
    print("Validating targets...")
    ok = validate_all()
    sys.exit(0 if ok else 1)