ADA-Python / app.py
ussu321's picture
Upload 50 files
bd86de0 verified
Raw
History Blame Contribute Delete
24.7 kB
#!/usr/bin/env python3
"""
================================================================================
USSU'S ULTRA PRO MAX ALGORITHM ANALYZER v4.0
Flask Cyberpunk Edition — Interactive Web Deploy Ready
Complete analysis of Graph Algorithms, Searching, Sorting, MST, Shortest Path,
Dynamic Programming, Greedy, Backtracking, ADA Theory, Math Tools,
Speed Benchmarking | Performance Profiling | Futuristic Glassmorphism UI
Author: Ussu (github.com/issu321)
Repo: https://github.com/issu321/Analysis-of-Algorithms
Kali Linux Compatible | Python 3.13 Ready | Windows 11 Ready
================================================================================
"""
import os
import sys
import json
import random
import math
from flask import Flask, render_template, request, jsonify, send_file
# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from utils.core import Graph, Colors
from utils.viz import (
fig_to_base64, plot_graph_cyber, plot_sorting_step, plot_sorting_frames,
plot_benchmark_bar, plot_benchmark_lines, plot_dp_table,
plot_asymptotic_growth, plot_recursion_tree
)
from algorithms.search import SearchingAlgorithms
from algorithms.sort import SortingAlgorithms
from algorithms.graph import GraphAlgorithms
from algorithms.dp import DynamicProgramming
from algorithms.greedy import GreedyAlgorithms
from algorithms.backtrack import BacktrackingAlgorithms
from algorithms.math_tools import MathTools
from algorithms.ada import ADATools
from algorithms.benchmark import BenchmarkSuite
app = Flask(__name__)
app.secret_key = "ussu-algorithm-analyzer-v4-flask-secret-key"
# Jinja2 globals for template safety
app.jinja_env.globals['float'] = float
app.jinja_env.globals['inf'] = float('inf')
app.jinja_env.globals['len'] = len
app.jinja_env.globals['zip'] = zip
# Custom Jinja2 filters
@app.template_filter('tojson_pretty')
def tojson_pretty(value):
return json.dumps(value, indent=2, default=str)
# ============================ HOME ============================
@app.route("/")
def home():
return render_template("home.html")
# ============================ GRAPH ============================
@app.route("/graph", methods=["GET", "POST"])
def graph_page():
result = None
graph_data = None
img_data = None
algo = request.form.get("algo", "bfs")
if request.method == "POST":
action = request.form.get("action", "")
if action == "create":
n = int(request.form.get("n", 5))
p = float(request.form.get("p", 0.3))
directed = request.form.get("directed") == "on"
weighted = request.form.get("weighted") == "on"
g = Graph.from_random(n, p, directed, weighted)
graph_data = g.to_dict()
result = {"message": f"Graph created: {len(g.vertices)}V {g.edge_count}E", "status": "ok"}
elif action == "custom":
edges_str = request.form.get("edges", "")
directed = request.form.get("directed") == "on"
weighted = request.form.get("weighted") == "on"
try:
g = Graph.from_edges(edges_str, directed, weighted)
graph_data = g.to_dict()
result = {"message": f"Custom graph: {len(g.vertices)}V {g.edge_count}E", "status": "ok"}
# Debug: ensure graph_data has content
if not graph_data.get("nodes"):
result = {"message": "No valid edges parsed. Check format: u v [w] per line", "status": "warning"}
graph_data = None
except Exception as e:
result = {"message": f"Error parsing edges: {str(e)}", "status": "error"}
graph_data = None
elif action == "run" and request.form.get("graph_json"):
g_dict = json.loads(request.form.get("graph_json"))
g = Graph(directed=g_dict.get("directed", False), weighted=g_dict.get("weighted", False))
for n in g_dict.get("nodes", []):
g.add_vertex(n["id"])
for e in g_dict.get("edges", []):
w = float(e["label"]) if e.get("label") and g.weighted else None
g.add_edge(e["from"], e["to"], w if w else 1.0)
ga = GraphAlgorithms()
start = int(request.form.get("start", 0))
target = request.form.get("target", "")
target = int(target) if target.strip() != "" else None
if algo == "bfs":
result = ga.bfs(g, start, target)
elif algo == "dfs_iter":
result = ga.dfs_iterative(g, start, target)
elif algo == "dfs_rec":
result = ga.dfs_recursive(g, start, target)
elif algo == "dijkstra":
result = ga.dijkstra(g, start, target)
elif algo == "bellman_ford":
result = ga.bellman_ford(g, start)
elif algo == "floyd_warshall":
result = ga.floyd_warshall(g)
elif algo == "prim":
result = ga.prim_mst(g)
elif algo == "kruskal":
result = ga.kruskal_mst(g)
elif algo == "topological":
result = ga.topological_sort(g)
elif algo == "kosaraju":
result = ga.kosaraju_scc(g)
elif algo == "astar":
result = ga.a_star(g, start, target if target else 0)
elif algo == "longest_path_dag":
result = ga.longest_path_dag(g, start)
graph_data = g.to_dict()
highlight_path = result.get("path", [])
highlight_nodes = result.get("traversal", []) if not highlight_path else []
fig = plot_graph_cyber(g, highlight_path=highlight_path if highlight_path else None,
highlight_nodes=highlight_nodes if highlight_nodes else None,
title=f"{result.get('algorithm', 'Graph')} Result")
img_data = fig_to_base64(fig)
return render_template("graph.html", result=result, graph_data=graph_data, img_data=img_data, algo=algo)
# ============================ SEARCH ============================
@app.route("/search", methods=["GET", "POST"])
def search_page():
result = None
compare_results = None
if request.method == "POST":
arr_str = request.form.get("arr", "1 3 5 7 9 11 13")
arr = list(map(int, arr_str.split()))
target = int(request.form.get("target", 7))
algo = request.form.get("algo", "binary")
searcher = SearchingAlgorithms()
if algo == "compare":
compare_results = searcher.compare_all(arr, target)
else:
algo_map = {
"linear": searcher.linear_search,
"binary": searcher.binary_search_iterative,
"binary_rec": searcher.binary_search_recursive,
"jump": searcher.jump_search,
"interpolation": searcher.interpolation_search,
"exponential": searcher.exponential_search,
"ternary": searcher.ternary_search,
"fibonacci": searcher.fibonacci_search,
}
if algo in algo_map:
result = algo_map[algo](arr, target)
return render_template("search.html", result=result, compare_results=compare_results)
# ============================ SORT ============================
@app.route("/sort", methods=["GET", "POST"])
def sort_page():
result = None
compare_results = None
step_images = None
if request.method == "POST":
arr_str = request.form.get("arr", "64 34 25 12 22 11 90")
arr = list(map(int, arr_str.split()))
algo = request.form.get("algo", "merge")
capture = request.form.get("capture_steps") == "on"
sorter = SortingAlgorithms(capture_steps=capture)
if algo == "compare":
compare_results = sorter.compare_all(arr)
else:
algo_map = {
"bubble": sorter.bubble_sort,
"selection": sorter.selection_sort,
"insertion": sorter.insertion_sort,
"merge": sorter.merge_sort,
"quick": sorter.quick_sort,
"heap": sorter.heap_sort,
"shell": sorter.shell_sort,
"cocktail": sorter.cocktail_shaker_sort,
"comb": sorter.comb_sort,
"counting": sorter.counting_sort,
"radix": sorter.radix_sort,
"bucket": lambda a: sorter.bucket_sort([float(x) for x in a]),
"timsort": sorter.tim_sort,
}
if algo in algo_map:
result = algo_map[algo](arr)
if capture and result.get("steps"):
step_images = plot_sorting_frames(result["steps"])
return render_template("sort.html", result=result, compare_results=compare_results, step_images=step_images)
# ============================ DP ============================
@app.route("/dp", methods=["GET", "POST"])
def dp_page():
result = None
dp_img = None
if request.method == "POST":
algo = request.form.get("algo", "knapsack")
dp = DynamicProgramming()
if algo == "knapsack":
w = list(map(int, request.form.get("weights", "2 3 4 5").split()))
v = list(map(int, request.form.get("values", "3 4 5 6").split()))
cap = int(request.form.get("capacity", 5))
result = dp.knapsack_01(w, v, cap)
if result.get("dp_table"):
fig = plot_dp_table(result["dp_table"], "0/1 Knapsack DP Table",
row_labels=[f"Item {i}" for i in range(len(w)+1)],
col_labels=[str(i) for i in range(cap+1)])
dp_img = fig_to_base64(fig)
elif algo == "unbounded_knapsack":
w = list(map(int, request.form.get("weights", "2 3 4 5").split()))
v = list(map(int, request.form.get("values", "3 4 5 6").split()))
cap = int(request.form.get("capacity", 5))
result = dp.knapsack_unbounded(w, v, cap)
elif algo == "lcs":
s1 = request.form.get("s1", "AGGTAB")
s2 = request.form.get("s2", "GXTXAYB")
result = dp.lcs(s1, s2)
if result.get("dp_table"):
fig = plot_dp_table(result["dp_table"], "LCS DP Table",
row_labels=[""] + list(s1),
col_labels=[""] + list(s2))
dp_img = fig_to_base64(fig)
elif algo == "edit_distance":
s1 = request.form.get("s1", "kitten")
s2 = request.form.get("s2", "sitting")
result = dp.edit_distance(s1, s2)
if result.get("dp_table"):
fig = plot_dp_table(result["dp_table"], "Edit Distance DP Table",
row_labels=[""] + list(s1),
col_labels=[""] + list(s2))
dp_img = fig_to_base64(fig)
elif algo == "matrix_chain":
dims = list(map(int, request.form.get("dims", "10 30 5 60").split()))
result = dp.matrix_chain_order(dims)
if result.get("dp_table"):
n = len(dims) - 1
fig = plot_dp_table(result["dp_table"], "Matrix Chain DP Table",
row_labels=[f"A{i+1}" for i in range(n)],
col_labels=[f"A{i+1}" for i in range(n)])
dp_img = fig_to_base64(fig)
elif algo == "coin_change_min":
coins = list(map(int, request.form.get("coins", "1 2 5").split()))
amt = int(request.form.get("amount", 11))
result = dp.coin_change_min(coins, amt)
elif algo == "coin_change_ways":
coins = list(map(int, request.form.get("coins", "1 2 5").split()))
amt = int(request.form.get("amount", 5))
result = dp.coin_change_ways(coins, amt)
elif algo == "lis":
arr = list(map(int, request.form.get("arr", "10 9 2 5 3 7 101 18").split()))
result = dp.lis(arr)
return render_template("dp.html", result=result, dp_img=dp_img)
# ============================ GREEDY ============================
@app.route("/greedy", methods=["GET", "POST"])
def greedy_page():
result = None
if request.method == "POST":
algo = request.form.get("algo", "activity")
greedy = GreedyAlgorithms()
if algo == "activity":
n = int(request.form.get("n", 4))
acts = []
for i in range(n):
s = int(request.form.get(f"start_{i}", 0))
f = int(request.form.get(f"finish_{i}", 0))
acts.append((s, f, f"A{i+1}"))
result = greedy.activity_selection(acts)
elif algo == "fractional_knapsack":
w = list(map(int, request.form.get("weights", "10 20 30").split()))
v = list(map(int, request.form.get("values", "60 100 120").split()))
cap = int(request.form.get("capacity", 50))
result = greedy.fractional_knapsack(w, v, cap)
elif algo == "huffman":
text = request.form.get("text", "hello world")
from collections import Counter
result = greedy.huffman_coding(dict(Counter(text)))
elif algo == "job_sequencing":
n = int(request.form.get("n", 3))
jobs = []
for i in range(n):
d = int(request.form.get(f"deadline_{i}", 0))
p = int(request.form.get(f"profit_{i}", 0))
jobs.append((f"J{i+1}", d, p))
result = greedy.job_sequencing(jobs)
elif algo == "min_coins":
coins = list(map(int, request.form.get("coins", "1 5 10 25").split()))
amount = int(request.form.get("amount", 30))
result = greedy.minimum_coins_greedy(coins, amount)
return render_template("greedy.html", result=result)
# ============================ BACKTRACK ============================
@app.route("/backtrack", methods=["GET", "POST"])
def backtrack_page():
result = None
if request.method == "POST":
algo = request.form.get("algo", "n_queens")
bt = BacktrackingAlgorithms()
if algo == "n_queens":
n = int(request.form.get("n", 8))
result = bt.n_queens(n)
elif algo == "sudoku":
grid = []
for i in range(9):
row = list(map(int, request.form.get(f"row_{i}", "0 0 0 0 0 0 0 0 0").split()))
grid.append(row)
result = bt.sudoku_solver(grid)
elif algo == "subset_sum":
arr = list(map(int, request.form.get("arr", "3 34 4 12 5 2").split()))
target = int(request.form.get("target", 9))
result = bt.subset_sum(arr, target)
elif algo == "graph_coloring":
n = int(request.form.get("n", 4))
m = int(request.form.get("m", 3))
adj = []
for i in range(n):
row = list(map(int, request.form.get(f"adj_row_{i}", "0 0 0 0").split()))
adj.append(row)
result = bt.graph_coloring(adj, m)
elif algo == "hamiltonian":
n = int(request.form.get("n", 4))
start = int(request.form.get("start", 0))
adj = []
for i in range(n):
row = list(map(int, request.form.get(f"ham_row_{i}", "0 0 0 0").split()))
adj.append(row)
result = bt.hamiltonian_cycle(adj, start)
return render_template("backtrack.html", result=result)
# ============================ MATH ============================
@app.route("/math", methods=["GET", "POST"])
def math_page():
result = None
if request.method == "POST":
algo = request.form.get("algo", "gcd")
mt = MathTools()
if algo == "factorial":
n = int(request.form.get("n", 5))
result = mt.factorial(n)
elif algo == "fibonacci":
n = int(request.form.get("n", 10))
method = request.form.get("method", "iterative")
result = mt.fibonacci(n, method)
elif algo == "gcd":
a = int(request.form.get("a", 48))
b = int(request.form.get("b", 18))
result = mt.gcd(a, b)
elif algo == "extended_gcd":
a = int(request.form.get("a", 48))
b = int(request.form.get("b", 18))
result = mt.extended_gcd(a, b)
elif algo == "fast_power":
b = float(request.form.get("base", 2))
e = int(request.form.get("exp", 10))
result = mt.fast_exponentiation(b, e)
elif algo == "modular_power":
base = int(request.form.get("base", 2))
exp = int(request.form.get("exp", 10))
mod = int(request.form.get("mod", 1000))
result = mt.modular_exponentiation(base, exp, mod)
elif algo == "is_prime":
n = int(request.form.get("n", 97))
result = mt.is_prime(n)
elif algo == "sieve":
n = int(request.form.get("n", 50))
result = mt.sieve_eratosthenes(n)
elif algo == "matrix_multiply":
A = [[float(request.form.get(f"a_{i}_{j}", 0)) for j in range(2)] for i in range(2)]
B = [[float(request.form.get(f"b_{i}_{j}", 0)) for j in range(2)] for i in range(2)]
result = mt.matrix_multiply(A, B)
elif algo == "tower_hanoi":
n = int(request.form.get("n", 3))
result = mt.tower_of_hanoi(n)
elif algo == "permutations":
arr = request.form.get("arr", "1 2 3").split()
result = mt.generate_permutations(arr)
return render_template("math.html", result=result)
# ============================ ADA ============================
@app.route("/ada", methods=["GET", "POST"])
def ada_page():
result = None
ref_data = None
if request.method == "POST":
algo = request.form.get("algo", "master")
ada = ADATools()
if algo == "master":
a = float(request.form.get("a", 2))
b = float(request.form.get("b", 2))
f = request.form.get("f", "n")
result = ada.master_theorem(a, b, f)
elif algo == "recursion_tree":
a = float(request.form.get("a", 2))
b = float(request.form.get("b", 2))
n = float(request.form.get("n", 16))
f_str = request.form.get("f_func", "n")
# Parse simple f(n)
if f_str == "n":
f_func = lambda x: x
elif f_str == "n^2":
f_func = lambda x: x**2
elif f_str == "1":
f_func = lambda x: 1
elif f_str == "n*log(n)":
f_func = lambda x: x * math.log(x) if x > 0 else 0
else:
f_func = lambda x: x
result = ada.recursion_tree_cost(a, b, f_func, n)
elif algo == "amortized_array":
n = int(request.form.get("n", 20))
result = ada.amortized_dynamic_array(n)
elif algo == "amortized_counter":
n_bits = int(request.form.get("n_bits", 8))
increments = int(request.form.get("increments", 20))
result = ada.amortized_binary_counter(n_bits, increments)
elif algo == "hiring":
n = int(request.form.get("n", 10))
result = ada.hiring_problem(n)
elif algo == "randomized_quicksort":
n = int(request.form.get("n", 100))
result = ada.randomized_quicksort_analysis(n)
else:
ada = ADATools()
ref_data = {
"big_o": ada.big_o_reference(),
"definitions": ada.asymptotic_definitions(),
"np": ada.np_completeness_reference(),
"paradigms": ada.paradigm_comparison(),
}
return render_template("ada.html", result=result, ref_data=ref_data)
# ============================ BENCHMARK ============================
@app.route("/benchmark", methods=["GET", "POST"])
def benchmark_page():
result = None
chart_img = None
if request.method == "POST":
suite = request.form.get("suite", "search")
bench = BenchmarkSuite()
if suite == "search":
sizes = [100, 1000, 5000, 10000]
result = bench.benchmark_search(sizes)
# Transform for line chart
chart_data = {}
for r in result:
for algo, t in r["times"].items():
chart_data.setdefault(algo, []).append({"size": r["size"], "time_ms": t})
fig = plot_benchmark_lines(chart_data, title="Search Benchmark Scaling")
chart_img = fig_to_base64(fig)
elif suite == "sort":
sizes = [100, 500, 1000, 2000]
result = bench.benchmark_sort(sizes)
chart_data = {}
for r in result:
for algo, t in r["times"].items():
chart_data.setdefault(algo, []).append({"size": r["size"], "time_ms": t})
fig = plot_benchmark_lines(chart_data, title="Sort Benchmark Scaling")
chart_img = fig_to_base64(fig)
elif suite == "graph":
sizes = [10, 20, 50, 100]
result = bench.benchmark_graph(sizes)
chart_data = {}
for r in result:
for algo in ["bfs", "dfs", "dijkstra"]:
chart_data.setdefault(algo.upper(), []).append({"size": r["size"], "time_ms": r[algo]})
fig = plot_benchmark_lines(chart_data, title="Graph Benchmark Scaling")
chart_img = fig_to_base64(fig)
elif suite == "dp":
sizes = [5, 10, 15, 20]
result = bench.benchmark_dp(sizes)
chart_data = {}
for r in result:
for algo in ["knapsack", "lcs"]:
chart_data.setdefault(algo.upper(), []).append({"size": r["size"], "time_ms": r[algo]})
fig = plot_benchmark_lines(chart_data, title="DP Benchmark Scaling")
chart_img = fig_to_base64(fig)
elif suite == "custom":
# Speed profile single algorithm
algo_name = request.form.get("custom_algo", "merge_sort")
size = int(request.form.get("size", 1000))
arr = [random.randint(0, size) for _ in range(size)]
sorter = SortingAlgorithms()
algo_map = {
"merge_sort": sorter.merge_sort,
"quick_sort": sorter.quick_sort,
"heap_sort": sorter.heap_sort,
"bubble_sort": sorter.bubble_sort,
}
if algo_name in algo_map:
result = bench.speed_profile(algo_map[algo_name], arr)
return render_template("benchmark.html", result=result, chart_img=chart_img)
# ============================ COMPARE ============================
@app.route("/compare", methods=["GET", "POST"])
def compare_page():
result = None
chart_img = None
if request.method == "POST":
category = request.form.get("category", "sort")
arr_str = request.form.get("arr", "64 34 25 12 22 11 90")
arr = list(map(int, arr_str.split()))
if category == "sort":
sorter = SortingAlgorithms()
result = sorter.compare_all(arr)
fig = plot_benchmark_bar(result, title="Sorting Algorithms Comparison")
chart_img = fig_to_base64(fig)
elif category == "search":
target = int(request.form.get("target", 7))
searcher = SearchingAlgorithms()
result = searcher.compare_all(arr, target)
fig = plot_benchmark_bar(result, title="Search Algorithms Comparison", metric="comparisons")
chart_img = fig_to_base64(fig)
return render_template("compare.html", result=result, chart_img=chart_img)
# ============================ API ENDPOINTS ============================
@app.route("/api/graph_random")
def api_graph_random():
n = int(request.args.get("n", 5))
p = float(request.args.get("p", 0.3))
directed = request.args.get("directed") == "true"
weighted = request.args.get("weighted") == "true"
g = Graph.from_random(n, p, directed, weighted)
return jsonify(g.to_dict())
@app.route("/api/health")
def health():
return jsonify({"status": "ok", "version": "4.0-flask"})
# ============================ MAIN ============================
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860))
app.run(host="0.0.0.0", port=port, debug=True)