fix: Make search work with automatic mode

This commit is contained in:
Leni Aniva 2024-09-13 17:54:11 -07:00
parent 6f4c26ecee
commit 8abe689a0a
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
3 changed files with 54 additions and 28 deletions

View File

@ -19,6 +19,7 @@ poetry build
To run server tests: To run server tests:
``` bash ``` bash
python -m pantograph.server python -m pantograph.server
python -m pantograph.search
``` ```
The tests in `pantograph/server.py` also serve as simple interaction examples The tests in `pantograph/server.py` also serve as simple interaction examples

View File

@ -21,7 +21,8 @@ class SearchState:
@property @property
def next_goal_id(self) -> int: def next_goal_id(self) -> int:
goal_id, _ = max([(i, prio) for i, prio in enumerate(self.priorities) if not self.solved[i]], goal_id, _ = max(
((i, prio) for i, prio in enumerate(self.priorities) if not self.solved[i]),
key=lambda x: x[1]) key=lambda x: x[1])
return goal_id return goal_id
@ -40,11 +41,20 @@ class SearchResult:
steps: int steps: int
class Agent: class Agent:
"""
An agent interface for proof search
"""
def next_tactic(self, state: GoalState, goal_id: int, informal_stmt:str, informal_proof:str) -> Optional[Tactic]: def next_tactic(
self,
state: GoalState,
goal_id: int,
informal_stmt: str,
informal_proof: str) -> Optional[Tactic]:
""" """
Implement this function to generate the next tactic for a goal Implement this function to generate the next tactic for a goal
""" """
return None
def guidance(self, state: GoalState) -> list[float]: def guidance(self, state: GoalState) -> list[float]:
""" """
@ -65,16 +75,22 @@ class Agent:
max_steps: int = 100, max_steps: int = 100,
max_trials_per_goal: int = 5, max_trials_per_goal: int = 5,
verbose: bool = False) -> SearchResult: verbose: bool = False) -> SearchResult:
"""
Searches using th
"""
assert server.is_automatic(), "Search must be run in automatic mode"
search_stack = [SearchState(state=server.goal_start(target), initial_state = SearchState(
state=server.goal_start(target),
parent=None, parent=None,
parent_goal_id=None, parent_goal_id=None,
priorities=[0.0])] priorities=[0.0]
)
search_stack = [initial_state]
""" """
Executes proof search on this state Executes proof search on this state
""" """
for i_step in range(max_steps): for i_step in range(max_steps):
assert search_stack, "No states in search stack" assert search_stack, "No states in search stack"
if verbose: if verbose:
@ -84,18 +100,8 @@ class Agent:
assert isinstance(search_state, SearchState) assert isinstance(search_state, SearchState)
if search_state.is_solved: if search_state.is_solved:
# if the state is solved, propagate this solved status
if search_state.is_root:
if verbose:
print("Search complete: Root state solved")
self.reset()
return SearchResult(success=True, steps=i_step) return SearchResult(success=True, steps=i_step)
search_stack.pop(-1)
assert not search_stack[search_state.parent].solved[search_state.parent_goal_id]
search_stack[search_state.parent].solved[search_state.parent_goal_id] = True
continue
# Find the unsolved goal with the highest priority # Find the unsolved goal with the highest priority
goal_id = search_state.next_goal_id goal_id = search_state.next_goal_id
@ -106,7 +112,8 @@ class Agent:
# Generate tactic for this goal # Generate tactic for this goal
tactic = self.next_tactic(search_state.state, goal_id, informal_stmt, informal_proof) tactic = self.next_tactic(search_state.state, goal_id, informal_stmt, informal_proof)
print("????next tactic: ", tactic) if verbose:
print(f"Next tactic: {tactic}")
if not tactic: if not tactic:
# pop the current state and continue to the next # pop the current state and continue to the next
search_stack.pop(-1) search_stack.pop(-1)
@ -128,12 +135,16 @@ class Agent:
if len(next_goal_state.goals) <= 1 else \ if len(next_goal_state.goals) <= 1 else \
self.guidance(next_goal_state) self.guidance(next_goal_state)
parent = len(search_stack) - 1 parent = len(search_stack) - 1
search_stack.append(SearchState(state=next_goal_state, next_state = SearchState(
state=next_goal_state,
parent=parent, parent=parent,
parent_goal_id=goal_id, parent_goal_id=goal_id,
priorities=priorities)) priorities=priorities
)
search_stack.append(next_state)
except TacticFailure as t: except TacticFailure as t:
if verbose:
print(f"Tactic failed: {t}") print(f"Tactic failed: {t}")
# try the next tactic. this one failed # try the next tactic. this one failed
@ -163,7 +174,12 @@ class DumbAgent(Agent):
"assumption", "assumption",
] ]
def next_tactic(self, state: GoalState, goal_id: int, informal_stmt:str, informal_proof:str) -> Optional[Tactic]: def next_tactic(
self,
state: GoalState,
goal_id: int,
informal_stmt: str,
informal_proof: str) -> Optional[Tactic]:
key = (state.state_id, goal_id) key = (state.state_id, goal_id)
i = self.goal_tactic_id_map[key] i = self.goal_tactic_id_map[key]
@ -188,14 +204,20 @@ class TestSearch(unittest.TestCase):
server = Server() server = Server()
agent = DumbAgent() agent = DumbAgent()
flag = agent.search(server=server, target="∀ (p q: Prop), p -> p", verbose=True) flag = agent.search(
server=server,
target="∀ (p q: Prop), p -> p",
verbose=False)
#flag = agent.search(server=server, target="∀ (p q: Prop), Or p q -> Or q p", verbose=True) #flag = agent.search(server=server, target="∀ (p q: Prop), Or p q -> Or q p", verbose=True)
self.assertTrue(flag) self.assertTrue(flag)
def test_solve_big(self): def test_solve_big(self):
server = Server() server = Server()
agent = DumbAgent() agent = DumbAgent()
flag = agent.search(server=server, target="∀ (p q: Prop), Or p q -> Or q p", verbose=True) flag = agent.search(
server=server,
target="∀ (p q: Prop), Or p q -> Or q p",
verbose=False)
self.assertTrue(flag) self.assertTrue(flag)

View File

@ -51,6 +51,9 @@ class Server:
# List of goal states that should be garbage collected # List of goal states that should be garbage collected
self.to_remove_goal_states = [] self.to_remove_goal_states = []
def is_automatic(self):
return self.options.get("automaticMode", True)
def restart(self): def restart(self):
if self.proc is not None: if self.proc is not None:
self.proc.close() self.proc.close()