From 8911aa729d68c30b15577fd8d9d4ed504a78e9f4 Mon Sep 17 00:00:00 2001 From: vncntt Date: Sat, 1 Mar 2025 22:12:13 -0800 Subject: [PATCH] added depth logic --- reasoning_gym/logic/knights_knaves.py | 88 +++++++++++++++++++++------ 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/reasoning_gym/logic/knights_knaves.py b/reasoning_gym/logic/knights_knaves.py index 802d3589..7cc16ecf 100644 --- a/reasoning_gym/logic/knights_knaves.py +++ b/reasoning_gym/logic/knights_knaves.py @@ -171,6 +171,7 @@ def _sample_statement(self, person_id: int, depth_constraint: int): while True: knight_or_knave = self.rng.choice(["telling-truth", "lying"]) person = self.rng.integers(0, self.n_people) + # prevent the contradiction "I am lying" if not (knight_or_knave == "lying" and person == person_id): return (knight_or_knave, person) if dice == 1: @@ -267,27 +268,78 @@ def format_problem(self): "solution_text": solution_text, } - def _format_statement(self, names, knight_knave, statement): + def _format_statement(self, names, knight_knave, statement, depth=0): + """ + Recursively format a logical statement with appropriate parentheses based on depth. + + Args: + names: List of people's names + knight_knave: Dictionary with knight/knave terminology + statement: Logical statement tuple to format + depth: Current nesting depth (0 = top level) + """ + # Base case: this is a primitive statement + if statement[0] in ("telling-truth", "lying"): + return self._format_knight_knave(names, knight_knave, statement) + + # Handle negation if statement[0] == "not": - return self._format_knight_knave(names, knight_knave, statement[1], negation=True) + + # Special case: If negating a primitive statement, use the complementary term directly + if statement[1][0] in ("telling-truth", "lying"): + # Map "telling-truth" to "lying" and vice versa + complementary_statement = ( + "lying" if statement[1][0] == "telling-truth" else "telling-truth", + statement[1][1], + ) + return self._format_knight_knave(names, knight_knave, complementary_statement) + else: + # For complex statements, use the verbose "it is not the case that" format + inner_content = self._format_statement(names, knight_knave, statement[1], depth + 1) + if statement[1][0] not in ("telling-truth", "lying"): + inner_content = f"({inner_content})" + return f"it is not the case that {inner_content}" + + # Handle AND/OR if statement[0] in ["and", "or"]: - return (" " + statement[0] + " ").join( - self._format_knight_knave(names, knight_knave, sub_stmt) for sub_stmt in statement[1:] - ) + formatted_substmts = [] + for sub_stmt in statement[1:]: + sub_content = self._format_statement(names, knight_knave, sub_stmt, depth + 1) + # Always add parentheses for complex subexpressions in AND/OR + if sub_stmt[0] not in ("telling-truth", "lying"): + sub_content = f"({sub_content})" + formatted_substmts.append(sub_content) + connector = f" {statement[0]} " + return connector.join(formatted_substmts) + + # Handle implication if statement[0] == "->": - return ( - "If " - + self._format_knight_knave(names, knight_knave, statement[1]) - + " then " - + self._format_knight_knave(names, knight_knave, statement[2]) - ) + antecedent = self._format_statement(names, knight_knave, statement[1], depth + 1) + consequent = self._format_statement(names, knight_knave, statement[2], depth + 1) + + # Always add parentheses for complex expressions in implications + if statement[1][0] not in ("telling-truth", "lying"): + antecedent = f"({antecedent})" + if statement[2][0] not in ("telling-truth", "lying"): + consequent = f"({consequent})" + + return f"if {antecedent} then {consequent}" + + # Handle biconditional if statement[0] == "<=>": - return ( - self._format_knight_knave(names, knight_knave, statement[1]) - + " if and only if " - + self._format_knight_knave(names, knight_knave, statement[2]) - ) - return self._format_knight_knave(names, knight_knave, statement) + left = self._format_statement(names, knight_knave, statement[1], depth + 1) + right = self._format_statement(names, knight_knave, statement[2], depth + 1) + + # Always add parentheses for complex expressions in biconditionals + if statement[1][0] not in ("telling-truth", "lying"): + left = f"({left})" + if statement[2][0] not in ("telling-truth", "lying"): + right = f"({right})" + + return f"{left} if and only if {right}" + + # This should not happen with well-formed statements + raise ValueError(f"Unknown statement type: {statement[0]}") def _format_knight_knave(self, names, knight_knave, statement, negation=False): assert statement[0] in ("telling-truth", "lying") @@ -394,8 +446,6 @@ def __generate_problem(self, rng: Random) -> dict[str, Any]: problems = sampler.sample_valid_problems(1, skip_no_solution=True, skip_multiple_solutions=True) problem = problems[0] - # Format the problem using the original KKProblemFormatter logic - # Format the problem formatter = KKProblemFormatter(rand_seed=rng.randint(0, 2**32), problem=problem) formatted = formatter.format_problem()