ds4dm / ecole

Extensible Combinatorial Optimization Learning Environments
https://www.ecole.ai
BSD 3-Clause "New" or "Revised" License
321 stars 68 forks source link

Khalil Features Reproducibility #314

Closed amf272 closed 2 years ago

amf272 commented 2 years ago

Describe the bug

When running an environment with the same seed by setting env.seed(43) and selecting the same actions (action_set[0]), I get different values for the khalil features.

Setting

To Reproduce

Unzip and run attached code test_khalil.zip with .lp file in same directory. Code is copied below for simplicity

Expected behavior

Should pass tests and have khalil features be the same from one run to the next or similar. They are sometimes wildly different, getting inf or nan in one run and 0 or normal numbers in another run.

import ecole
import numpy as np

def get_step_outputs():
    outputs = []
    lp_file = "test.lp"

    env = ecole.environment.Branching(
        pseudo_candidates=True,
        observation_function={
            "khalil": ecole.observation.Khalil2016(pseudo_candidates=True),
        },
        scip_params={
            "randomization/permuteconss": False,
    })

    env.seed(42)

    # for _ in range(30):
    # for _ in range(1):
    observation, action_set, reward_offset, done, info = env.reset(lp_file)
    outputs.append(dict(
        observation=observation, action_set=action_set, reward_offset=reward_offset, done=done, info=info
    ))
    while not done:
        observation, action_set, reward, done, info = env.step(action_set[0])
        outputs.append(dict(
        observation=observation, action_set=action_set, reward_offset=reward_offset, done=done, info=info
    ))
    return outputs

outputs1 = get_step_outputs()
outputs2 = get_step_outputs()

for out1, out2 in zip(outputs1, outputs2):

    # action sets are the same
    assert np.array_equal(out1["action_set"], out2["action_set"]), f"actions sets are not the same!"
    print(out1["action_set"].shape, out1["observation"]["khalil"].features.shape)
    khalil1 = out1["observation"]["khalil"].features
    khalil2 = out2["observation"]["khalil"].features
    try:
        assert np.allclose(khalil1, khalil2, equal_nan=True), "khalil features are different!"
    except Exception as e:
        different_inds = ~np.isclose(khalil1, khalil2, equal_nan=True)
        print(different_inds.shape)
        print(f"features with different values:", np.nonzero(different_inds.any(axis=0)))
        print("features diff:")
        print(np.stack([khalil1[different_inds], khalil2[different_inds]]).T)
        raise e