Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,144 +1,109 @@
|
|
1 |
-
from google import genai
|
2 |
-
from google.genai import types
|
3 |
import gradio as gr
|
4 |
import os
|
5 |
|
|
|
6 |
|
|
|
|
|
|
|
7 |
|
8 |
-
|
9 |
-
from
|
10 |
-
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
return response.text
|
17 |
-
|
18 |
-
def pvsnp(problem):
|
19 |
-
classification = llm_response(f'''
|
20 |
-
You are an expert in computational complexity theory, specializing in both classical complexity classes (P, NP, NP-complete, NP-hard) and modern developments (e.g., parameterized complexity, fine-grained complexity, Minimum Circuit Size Problem).
|
21 |
-
|
22 |
-
Your task is to classify a given problem into one of the following categories:
|
23 |
-
|
24 |
-
P: Solvable in deterministic polynomial time.
|
25 |
-
|
26 |
-
NP: Verifiable in polynomial time.
|
27 |
-
|
28 |
-
NP-complete: Both in NP and NP-hard.
|
29 |
-
|
30 |
-
NP-hard: At least as hard as NP-complete problems, possibly outside NP.
|
31 |
-
|
32 |
-
Beyond NP: Likely in PSPACE, EXPTIME, or undecidable.
|
33 |
-
|
34 |
-
Other: Fits alternative complexity classes (e.g., BPP, co-NP).
|
35 |
-
|
36 |
-
Problem Description:
|
37 |
-
{problem}
|
38 |
-
|
39 |
-
If the given problem is a NP-hard problem, decompose the NP-hard problem into polynomial-time solvable subproblems without solving them.
|
40 |
-
|
41 |
-
🔹 Inputs:
|
42 |
-
A formal definition and instance of the NP-hard problem (e.g., SAT, TSP, Graph Coloring).
|
43 |
-
|
44 |
-
Optional: Constraints or domain knowledge.
|
45 |
-
|
46 |
-
🔹 Decomposition Process:
|
47 |
-
Graph Representation & Structural Analysis
|
48 |
-
|
49 |
-
Convert the problem into a graph (if applicable).
|
50 |
-
|
51 |
-
Identify independent or tractable substructures.
|
52 |
-
|
53 |
-
Classification of Subproblems
|
54 |
-
|
55 |
-
Detect polynomially solvable parts (e.g., tree structures, bipartite graphs).
|
56 |
-
|
57 |
-
Separate them from harder components.
|
58 |
-
|
59 |
-
Partitioning & Transformation
|
60 |
-
|
61 |
-
Break the problem into independent or loosely connected subproblems.
|
62 |
-
|
63 |
-
Ensure each subproblem is in P or provably easier than the original.
|
64 |
-
|
65 |
-
Output a structured breakdown.
|
66 |
-
|
67 |
-
🔹 Outputs:
|
68 |
-
A list of P-complexity subproblems.
|
69 |
-
|
70 |
-
A dependency graph of their relationships in ASCII format.
|
71 |
-
|
72 |
-
A complexity analysis report quantifying decomposition effectiveness.
|
73 |
-
|
74 |
-
Guidelines for Classification:
|
75 |
-
Problem Analysis
|
76 |
-
|
77 |
-
Determine if the problem is a decision, optimization, or function computation problem.
|
78 |
-
|
79 |
-
Identify key input/output characteristics and constraints.
|
80 |
-
|
81 |
-
Complexity Insights
|
82 |
-
|
83 |
-
Check for polynomial-time solvability via known techniques (dynamic programming, greedy methods).
|
84 |
-
|
85 |
-
Assess reductions to/from well-studied problems.
|
86 |
-
|
87 |
-
Advanced Considerations
|
88 |
-
|
89 |
-
Incorporate recent research (e.g., MCSP's implications for NP-completeness).
|
90 |
-
|
91 |
-
Evaluate parameterized complexity (FPT results) and fine-grained complexity (SETH, other conjectures).
|
92 |
-
|
93 |
-
Consider probabilistic or average-case complexity aspects.
|
94 |
-
|
95 |
-
Justification
|
96 |
-
|
97 |
-
Provide a concise explanation for the classification, referencing key problem features and relevant research.
|
98 |
-
|
99 |
-
Your Classification and Explanation:
|
100 |
-
''')
|
101 |
-
|
102 |
-
return classification
|
103 |
-
|
104 |
-
def critic_analysis(classification_output):
|
105 |
-
critic = llm_response(f'''"You are PolyCritic, an expert in computational complexity and problem decomposition. Your goal is to critically evaluate whether a given
|
106 |
-
NP-hard problem, when broken into P-solvable subproblems, can be efficiently recombined to yield the full solution. Here is the problem and the analysis: {classification_output}
|
107 |
-
|
108 |
-
Instructions:
|
109 |
-
1️⃣ Input: A decomposed NP-hard problem along with its P-solvable subproblems.
|
110 |
-
2️⃣ Step 1 - Validate Subproblems:
|
111 |
-
|
112 |
-
Do these subproblems fully cover the original problem?
|
113 |
-
|
114 |
-
Are they correctly categorized as P?
|
115 |
-
3️⃣ Step 2 - Analyze Recombination Complexity:
|
116 |
-
|
117 |
-
Can the subproblem solutions be combined in polynomial time?
|
118 |
-
|
119 |
-
If not, what is the bottleneck? (e.g., exponential merging, missing constraints)
|
120 |
-
4️⃣ Step 3 - Provide Verdict:
|
121 |
-
|
122 |
-
If recombination is efficient, explain why this suggests progress towards P = NP.
|
123 |
-
|
124 |
-
If inefficient, identify where complexity remains and suggest next steps.
|
125 |
-
5️⃣ Step 4 - Provide Complexity Insights:
|
126 |
-
|
127 |
-
Offer insights into whether certain structural patterns predict efficient recombination.
|
128 |
-
|
129 |
-
Suggest improvements in decomposition strategies.
|
130 |
-
|
131 |
-
Example Analysis Format:
|
132 |
-
💡 Problem: Traveling Salesperson (TSP)
|
133 |
-
🔍 Subproblems: Shortest paths between city clusters (P-solvable)
|
134 |
-
⚖ Recombination Complexity: Exponential growth in possible paths when merging clusters
|
135 |
-
🚨 Verdict: Recombination remains NP-hard → Decomposition needs refinement
|
136 |
|
137 |
-
|
138 |
-
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
141 |
-
'''
|
142 |
iface = gr.Interface(
|
143 |
fn=pvsnp,
|
144 |
inputs=gr.Textbox(label="What problem would you like to classify as P or NP?"),
|
@@ -150,29 +115,4 @@ iface = gr.Interface(
|
|
150 |
)
|
151 |
|
152 |
# Launch the app
|
153 |
-
iface.launch()
|
154 |
-
|
155 |
-
with gr.Blocks(theme=gr.themes.Ocean()) as app:
|
156 |
-
gr.Markdown("# PolyProb & PolyCritic AI 🤖")
|
157 |
-
gr.Markdown('''PolyProb and PolyCritic are AI Agents that help users classify a problem into categories such as P, NP, NP-complete, NP-hard while
|
158 |
-
providing clear, concise explanations of its reasoning. As part of AI Quotient’s Millennium Math Challenge, it is the first step towards solving the P vs NP problem.''')
|
159 |
-
|
160 |
-
with gr.Row():
|
161 |
-
problem_input = gr.Textbox(label="Enter a computational problem")
|
162 |
-
classify_button = gr.Button("Classify")
|
163 |
-
|
164 |
-
classification_output = gr.Markdown(label="Classification (P or NP)")
|
165 |
-
|
166 |
-
classify_button.click(pvsnp, inputs=problem_input, outputs=[classification_output])
|
167 |
-
|
168 |
-
evaluate_button = gr.Button("Evaluate Recombination Complexity")
|
169 |
-
recombination_output = gr.Textbox(label="Recombination Complexity")
|
170 |
-
|
171 |
-
evaluate_button.click(critic_analysis, inputs=classification_output, outputs=recombination_output)
|
172 |
-
|
173 |
-
#results_button = gr.Button("Show Stored Results")
|
174 |
-
#results_display = gr.Textbox(label="Stored Results")
|
175 |
-
|
176 |
-
#results_button.click(get_stored_results, outputs=results_display)
|
177 |
-
|
178 |
-
app.launch()
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
import os
|
3 |
|
4 |
+
os.environ["OPENAI_API_KEY"] = os.getenv('api_key')
|
5 |
|
6 |
+
import math
|
7 |
+
import types
|
8 |
+
import uuid
|
9 |
|
10 |
+
from langchain.chat_models import init_chat_model
|
11 |
+
from langchain.embeddings import init_embeddings
|
12 |
+
from langgraph.store.memory import InMemoryStore
|
13 |
|
14 |
+
from langgraph_bigtool import create_agent
|
15 |
+
from langgraph_bigtool.utils import (
|
16 |
+
convert_positional_only_function_to_tool
|
17 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
+
# Collect functions from `math` built-in
|
20 |
+
all_tools = []
|
21 |
+
for function_name in dir(math):
|
22 |
+
function = getattr(math, function_name)
|
23 |
+
if not isinstance(
|
24 |
+
function, types.BuiltinFunctionType
|
25 |
+
):
|
26 |
+
continue
|
27 |
+
# This is an idiosyncrasy of the `math` library
|
28 |
+
if tool := convert_positional_only_function_to_tool(
|
29 |
+
function
|
30 |
+
):
|
31 |
+
all_tools.append(tool)
|
32 |
+
|
33 |
+
# Create registry of tools. This is a dict mapping
|
34 |
+
# identifiers to tool instances.
|
35 |
+
tool_registry = {
|
36 |
+
str(uuid.uuid4()): tool
|
37 |
+
for tool in all_tools
|
38 |
+
}
|
39 |
+
|
40 |
+
# Index tool names and descriptions in the LangGraph
|
41 |
+
# Store. Here we use a simple in-memory store.
|
42 |
+
embeddings = init_embeddings("openai:text-embedding-3-small")
|
43 |
+
|
44 |
+
store = InMemoryStore(
|
45 |
+
index={
|
46 |
+
"embed": embeddings,
|
47 |
+
"dims": 1536,
|
48 |
+
"fields": ["description"],
|
49 |
+
}
|
50 |
+
)
|
51 |
+
for tool_id, tool in tool_registry.items():
|
52 |
+
store.put(
|
53 |
+
("tools",),
|
54 |
+
tool_id,
|
55 |
+
{
|
56 |
+
"description": f"{tool.name}: {tool.description}",
|
57 |
+
},
|
58 |
+
)
|
59 |
+
|
60 |
+
# Initialize agent
|
61 |
+
llm = init_chat_model("openai:gpt-4o-mini")
|
62 |
+
|
63 |
+
builder = create_agent(llm, tool_registry)
|
64 |
+
agent = builder.compile(store=store)
|
65 |
+
|
66 |
+
from langchain_core.tools import Tool
|
67 |
+
import sympy
|
68 |
+
from sympy import symbols
|
69 |
+
|
70 |
+
def make_sympy_tool(func, name, description):
|
71 |
+
def _tool(expr: str) -> str:
|
72 |
+
local_symbols = symbols("x y z a b c n")
|
73 |
+
parsed_expr = sympy.sympify(expr, locals={s.name: s for s in local_symbols})
|
74 |
+
result = func(parsed_expr)
|
75 |
+
return str(result)
|
76 |
+
|
77 |
+
return Tool.from_function(
|
78 |
+
name=name,
|
79 |
+
description=description,
|
80 |
+
func=_tool
|
81 |
+
)
|
82 |
+
|
83 |
+
from sympy import simplify, expand, factor
|
84 |
+
|
85 |
+
sympy_tools = [
|
86 |
+
make_sympy_tool(simplify, "simplify", "Simplifies a symbolic expression"),
|
87 |
+
make_sympy_tool(expand, "expand", "Expands a symbolic expression"),
|
88 |
+
make_sympy_tool(factor, "factor", "Factors a symbolic expression"),
|
89 |
+
]
|
90 |
+
|
91 |
+
for tool in sympy_tools:
|
92 |
+
tool_id = str(uuid.uuid4())
|
93 |
+
tool_registry[tool_id] = tool
|
94 |
+
store.put(
|
95 |
+
("tools",),
|
96 |
+
tool_id,
|
97 |
+
{"description": f"{tool.name}: {tool.description}"},
|
98 |
+
)
|
99 |
+
|
100 |
+
builder = create_agent(llm, tool_registry)
|
101 |
+
agent = builder.compile(store=store)
|
102 |
+
|
103 |
+
|
104 |
+
|
105 |
+
|
106 |
|
|
|
107 |
iface = gr.Interface(
|
108 |
fn=pvsnp,
|
109 |
inputs=gr.Textbox(label="What problem would you like to classify as P or NP?"),
|
|
|
115 |
)
|
116 |
|
117 |
# Launch the app
|
118 |
+
iface.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|