"""Quick sanity check: verify Gym->DiscoRL adapter and agent initialization work. This script runs a minimal test without full training, just to ensure: 1. Environment adapter creates correctly 2. Agent initializes with correct specs 3. Forward pass (reset + a few steps) works 4. Disco103 weights load (if available) """ import os import sys import numpy as np # Force JAX to use CPU only (avoid GPU memory issues) os.environ['JAX_PLATFORMS'] = 'cpu' current_dir = os.path.dirname(os.path.abspath(__file__)) repo_root = os.path.abspath(os.path.join(current_dir, os.pardir)) sys.path.insert(0, os.path.join(repo_root, 'disco_rl')) import jax import jax.numpy as jnp from disco_rl import agent as disco_agent from disco_rl import types from disco_cartpole_env import DiscoCartPoleEnv from disco_weights import load_disco103_weights def test_env_creation(): """Test 1: Create DiscoCartPoleEnv.""" print('\n' + '='*60) print('Test 1: Environment Creation') print('='*60) try: env = DiscoCartPoleEnv(batch_size=2) print('✓ DiscoCartPoleEnv created successfully') obs_spec = env.single_observation_spec() act_spec = env.single_action_spec() print(f' Single obs spec: {obs_spec}') print(f' Single act spec: {act_spec}') # Check specs assert 'observation' in obs_spec, 'obs spec must have "observation" key' print('✓ Observation spec has correct structure') assert act_spec.dtype == np.int32, 'action spec must be int32' assert act_spec.shape == (), 'action spec must be scalar' print('✓ Action spec is scalar discrete (int32)') return env except Exception as e: print(f'✗ Environment creation failed: {e}') import traceback traceback.print_exc() return None def test_env_reset_step(env): """Test 2: Reset and step environment.""" print('\n' + '='*60) print('Test 2: Environment Reset & Step') print('='*60) try: _, timestep = env.reset() print('✓ Environment reset') # Check timestep structure assert isinstance(timestep, types.EnvironmentTimestep), 'timestep must be EnvironmentTimestep' print('✓ Timestep has correct type') obs = timestep.observation['observation'] print(f' Observation shape: {obs.shape}') print(f' Observation dtype: {obs.dtype}') print(f' Observation range: [{jnp.min(obs):.3f}, {jnp.max(obs):.3f}]') # Step with random actions batch_size = env.batch_size actions = jnp.array([0, 1], dtype=jnp.int32)[:batch_size] _, timestep_next = env.step(None, actions) print(f'✓ Environment stepped with actions {actions}') print(f' Reward shape: {timestep_next.reward.shape}') print(f' Reward values: {timestep_next.reward}') return True except Exception as e: print(f'✗ Reset/step failed: {e}') import traceback traceback.print_exc() return False def test_agent_creation(env): """Test 3: Create DiscoRL agent.""" print('\n' + '='*60) print('Test 3: DiscoRL Agent Creation') print('='*60) try: settings = disco_agent.get_settings_disco() print('✓ Loaded Disco agent settings') agent = disco_agent.Agent( single_observation_spec=env.single_observation_spec(), single_action_spec=env.single_action_spec(), agent_settings=settings, batch_axis_name=None, ) print('✓ DiscoRL Agent created') # Initialize states rng = jax.random.PRNGKey(0) rng, subkey = jax.random.split(rng) learner_state = agent.initial_learner_state(subkey) print('✓ Learner state initialized') rng, subkey = jax.random.split(rng) actor_state = agent.initial_actor_state(subkey) print('✓ Actor state initialized') return agent, learner_state, actor_state, rng except Exception as e: print(f'✗ Agent creation failed: {e}') import traceback traceback.print_exc() return None, None, None, None def test_agent_forward(env, agent, learner_state, actor_state, rng): """Test 4: Agent forward pass.""" print('\n' + '='*60) print('Test 4: Agent Forward Pass') print('='*60) try: _, env_t = env.reset() print('✓ Environment reset for agent test') rng, subkey = jax.random.split(rng) actor_timestep, new_actor_state = agent.actor_step( learner_state.params, subkey, env_t, actor_state, ) print('✓ Agent step completed') print(f' Action shape: {actor_timestep.actions.shape}') print(f' Action dtype: {actor_timestep.actions.dtype}') print(f' Sample action: {actor_timestep.actions[0]}') # Verify action is valid discrete index action = int(actor_timestep.actions[0]) num_actions = env.single_action_spec().maximum + 1 assert 0 <= action < num_actions, f'Action {action} out of range [0, {num_actions})' print(f'✓ Action is valid discrete index (0 <= {action} < {num_actions})') # Try a few more steps for step in range(3): rng, subkey = jax.random.split(rng) actor_timestep, new_actor_state = agent.actor_step( learner_state.params, subkey, env_t, new_actor_state, ) _, env_t = env.step(None, actor_timestep.actions) print(f'✓ Ran 3 more agent steps successfully') return True except Exception as e: print(f'✗ Agent forward pass failed: {e}') import traceback traceback.print_exc() return False def test_weights_loading(): """Test 5: Load Disco103 weights.""" print('\n' + '='*60) print('Test 5: Disco103 Weights Loading') print('='*60) try: weights = load_disco103_weights( disco_rl_path=os.path.join(repo_root, 'disco_rl') ) print('✓ Disco103 weights loaded successfully') return True except FileNotFoundError as e: print(f'⚠ Disco103 weights not found (this is OK for PoC): {e}') return False except Exception as e: print(f'✗ Weight loading failed: {e}') import traceback traceback.print_exc() return False def main(): print('='*60) print('DiscoRL CartPole Sanity Check') print('='*60) # Test 1: Environment env = test_env_creation() if env is None: print('\n✗ Critical: Environment creation failed. Cannot proceed.') return False # Test 2: Reset/Step if not test_env_reset_step(env): print('\n✗ Critical: Environment reset/step failed.') return False # Test 3: Agent agent, learner_state, actor_state, rng = test_agent_creation(env) if agent is None: print('\n✗ Critical: Agent creation failed.') return False # Test 4: Agent forward if not test_agent_forward(env, agent, learner_state, actor_state, rng): print('\n✗ Critical: Agent forward pass failed.') return False # Test 5: Weights test_weights_loading() # Summary print('\n' + '='*60) print('Sanity Check Complete') print('='*60) print('✓ All core components working!') print('\nNext steps:') print(' 1. Run: python3 train_disco_cartpole.py') print(' 2. Run: python3 eval_disco_vs_sb3.py') return True if __name__ == '__main__': success = main() sys.exit(0 if success else 1)