def test_reflection_asymmetry():
    """
    create a bunch of chairs and a table. The chairs are reflected along the long part of the table.
    check that the asymmetry score is 0
    """
    scores = []
    butil.clear_scene()
    obj_states = {}

    table = bbox_mesh_from_hipoly(TableDiningFactory(0), 0, use_pholder=False)
    obj_states[table.name] = ObjectState(table, tags={t.Semantics.Table})

    chairs = []
    for i in range(4):
        chair = bbox_mesh_from_hipoly(ChairFactory(0), i, use_pholder=False)
        obj_states[chair.name] = ObjectState(chair, tags={t.Semantics.Chair})
        chairs.append(chair)
        # tagging.tag_canonical_surfaces(chair)
        # tagging.extract_tagged_faces(chair, {t.Semantics.Front})
    chairs[0].location = (1, 1, 0)
    chairs[1].location = (1, -1, 0)
    chairs[2].location = (-1, 1, 0)
    chairs[3].location = (-1, -1, 0)

    chairs[0].rotation_euler = (0, 0, -np.pi / 2)
    chairs[1].rotation_euler = (0, 0, np.pi / 2)
    chairs[2].rotation_euler = (0, 0, -np.pi / 2)
    chairs[3].rotation_euler = (0, 0, np.pi / 2)

    bpy.context.view_layer.update()
    # chairs[0].rotation_euler = (0, 0, np.pi)

    # butil.save_blend('table_chairs.blend')

    state = State(objs=obj_states)

    # tagging.tag_canonical_surfaces(table)
    # for i in range(5):
    #     tagging.tag_canonical_surfaces(obj_states[f'chair{i}'].obj)

    constraints = []
    score_terms = []
    scene = cl.scene()
    table_tagged = cl.tagged(scene, {t.Semantics.Table})
    chairs_tagged = cl.tagged(scene, {t.Semantics.Chair})

    score_terms += [cl.reflectional_asymmetry(chairs_tagged, table_tagged)]
    problem = cl.Problem(constraints, score_terms)
    res = evaluate.evaluate_problem(problem, state).loss()
    scores.append(res)
    print(res)
    assert np.isclose(res, 0, atol=1e-2)

    # assert the asymmetry increases as we gradually move one chair away from the table
    chairs[0].location = (1, 2, 0)
    bpy.context.view_layer.update()
    score_terms = []
    score_terms += [cl.reflectional_asymmetry(chairs_tagged, table_tagged)]
    problem = cl.Problem(constraints, score_terms)
    res = evaluate.evaluate_problem(problem, state).loss()
    scores.append(res)

    # assert the asymmetry increases if we rotate chair 0
    chairs[0].rotation_euler = (0, 0, 0)
    bpy.context.view_layer.update()
    score_terms = []
    score_terms += [cl.reflectional_asymmetry(chairs_tagged, table_tagged)]
    problem = cl.Problem(constraints, score_terms)
    res = evaluate.evaluate_problem(problem, state).loss()
    scores.append(res)

    print("asymmetry scores", scores)
    # assert monotonocity
    assert scores == sorted(scores)
    # assert it is strict
    assert (scores[0] < scores[1]) and scores[1] < scores[2]

    create a bunch of chairs and a table. The chairs are reflected along the long part of the table.
    check that the asymmetry score is 0
    
tests/solver/test_constraint_evaluator.py