#!/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)