সরাসরি পর্বে যান
পর্ব ৫৮ · ৮৩-এর মধ্যে · মডিউল ১০

গ্রাফের representation আর isomorphism

Graph Representation and Isomorphism — Adjacency Lists and Matrices, Incidence Matrices, Invariants, Automorphisms, Canonical Forms and the Petersen Graph

Taught in Bangla, this lesson writes one graph as an edge list, adjacency list, adjacency matrix and incidence matrix, and reads degrees, walks and triangles from matrix powers, including trace(A cubed) and BB-transpose = D + A. It proves isomorphism with an explicit bijection and non-isomorphism with an invariant, shows that the prism and K(3,3) share invariants, counts labelled copies as n!/|Aut(G)|, and builds canonical forms. In-page Python runs a pruned isomorphism search and checks the Petersen graph.

এই পর্বে যা শিখবেন

  • Edge list, adjacency list, adjacency matrix আর incidence matrix বানানো, আর তাদের মধ্যের সম্পর্কগুলো প্রমাণ করা
  • Matrix থেকে degree, walk আর triangle গোনা, আর কোন representation কখন ভালো তা জায়গা-সময়ের হিসাবে বাছা
  • Isomorphism-এর নির্ভুল সংজ্ঞা, bijection বানিয়ে isomorphic প্রমাণ, আর invariant দিয়ে অ-isomorphic প্রমাণ
  • Automorphism, লেবেলযুক্ত বনাম লেবেলহীন গ্রাফ গোনা (n!/|Aut|), আর canonical form-এর ধারণা
  • Petersen graph-এর ধর্মগুলোর প্রমাণ, আর graph isomorphism সমস্যার জটিলতার বর্তমান অবস্থা

১ · গ্রাফ লিখে রাখার উপায় — edge list, adjacency list আর adjacency matrix

পর্ব ৫৭ “গ্রাফ — সংজ্ঞা, degree আর handshake theorem”-এ গ্রাফকে ছবি হিসেবে দেখা হয়েছে: কিছু বিন্দু আর তাদের জোড়া দেওয়া রেখা। কিন্তু ছবি কম্পিউটারে রাখা যায় না, আর হাতে আঁকা ছবি দেখে বড় গ্রাফ সম্পর্কে কিছু প্রমাণও করা যায় না। তাই প্রথম প্রশ্ন: একই গ্রাফকে সংখ্যা আর তালিকা দিয়ে কীভাবে লিখি, আর প্রতিটি লেখার ধরন থেকে কোন তথ্য সহজে পড়া যায়?

বাজারঘরের ঢাকা অফিসে কয়েকটি ডেলিভারি হাবের মধ্যে কোন কোন জোড়ায় সরাসরি ভ্যান চলে, তা তিনভাবে লেখা যায়। প্রথম: রুটের খাতা, প্রতি লাইনে একটি রুট (“ঢাকা–গাজীপুর”)। দ্বিতীয়: প্রতিটি হাবের নোটিশ বোর্ডে “এখান থেকে সরাসরি যায়” তালিকা। তৃতীয়: অফিসের দেয়ালে একটি বড় ছক, সারি আর কলামে সব হাব, আর যে ঘরে রুট আছে সেখানে টিক চিহ্ন। তিনটিতে একই তথ্য, কিন্তু “গাজীপুর থেকে কোথায় যাওয়া যায়?” প্রশ্নের উত্তর দ্বিতীয়টিতে এক নজরে, আর “সাভার–মুন্সিগঞ্জ রুট আছে কি?” প্রশ্নের উত্তর তৃতীয়টিতে এক ঘর দেখেই।

এই পর্বে “গ্রাফ” বললে, আলাদা করে না বললে, বোঝাবে একটি simple graph G = (V, E): vertex-এর একটি সসীম সেট V, আর edge-এর সেট E, যার প্রতিটি সদস্য V-এর দুটি আলাদা উপাদানের একটি অক্রমজোড়া {u, v}. অর্থাৎ self-loop নেই, একই জোড়ার মধ্যে একাধিক edge নেই, আর edge-এর দিক নেই। n = |V| আর m = |E| লিখব। Vertex v-এর degree deg(v) হলো v যত edge-এর প্রান্ত, তার সংখ্যা। Multigraph আর directed graph-এর ক্ষেত্রে কী বদলায়, তা প্রতিটি উপপাদ্যের পরে আলাদা করে বলা হবে।

সংজ্ঞা ১.১ (তিনটি representation)

V = {v1, …, vn} আর E = {e1, …, em} হলে

  • Edge list: E-এর সদস্যদের একটি তালিকা, যেমন [{v1, v2}, {v1, v3}, …].
  • Adjacency list: প্রতিটি v-এর জন্য তার প্রতিবেশীদের সেট N(v) = {u : {u, v} ∈ E}.
  • Adjacency matrix: n × n matrix A, যেখানে aij = 1 যদি {vi, vj} ∈ E, নইলে aij = 0.

Adjacency matrix প্রথম দেখা গেছে পর্ব ১৯ “Discrete math-এ matrix — 0-1 matrix আর Boolean product”-এ, directed graph-এর জন্য; আর পর্ব ৫২-এ একটি relation-এর zero-one matrix হিসেবে। Undirected simple graph-এ এর দুটি বিশেষ ধর্ম আছে, যা সংজ্ঞা থেকেই আসে।

উপপাদ্য ১.২ (simple graph-এর adjacency matrix)

(ক) A symmetric: A = AT, আর কর্ণের সব ঘর 0. (খ) সারি i-এর যোগফল deg(vi), আর সব ঘরের যোগফল 2m.

  1. {vi, vj} অক্রমজোড়া, তাই {vi, vj} = {vj, vi}, অর্থাৎ aij = aji. Self-loop নেই, তাই aii = 0. — simple graph-এর সংজ্ঞা
  2. সারি i-তে 1 ঠিক সেই j-গুলোতে, যেখানে vj ∈ N(vi); তাই সারির যোগফল |N(vi)| = deg(vi). — simple graph-এ প্রতিটি প্রতিবেশী একটি edge
  3. প্রতিটি edge {vi, vj} matrix-এ ঠিক দুটি 1 দেয় (ঘর ij আর ji), তাই সব ঘরের যোগফল 2m; আর ধাপ ২ অনুযায়ী একই যোগফল ∑deg(v). ∎ — দুইভাবে গোনা

ধাপ ৩ আসলে handshake theorem (∑deg(v) = 2m)-এর আরেকটি প্রমাণ: একই সংখ্যা দুইভাবে গোনা, ঠিক পর্ব ৩৭-এর double counting. Directed graph-এ A সাধারণত symmetric নয়; সারির যোগফল out-degree আর কলামের যোগফল in-degree. Multigraph-এ aij হয় vi আর vj-এর মধ্যের edge-এর সংখ্যা, তখন A আর 0-1 matrix থাকে না।

A-এর ঘাত: walk গোনা

পর্ব ১৯-এ প্রমাণ হয়েছে: (Ak)ij হলো vi থেকে vj-তে দৈর্ঘ্য k-এর walk-এর সংখ্যা। প্রমাণটি এখানে আবার করব না, শুধু তিনটি ফল নেব, যা এই পর্বে বারবার লাগবে।

ফল ১.৩ (simple graph-এ A2 আর A3)

(ক) (A2)ii = deg(vi); i ≠ j হলে (A2)ij = vi আর vj-এর সাধারণ প্রতিবেশীর সংখ্যা। (খ) trace(A2) = 2m. (গ) trace(A3) = 6t, যেখানে t হলো triangle (তিনটি vertex, প্রতি জোড়ায় edge)-এর সংখ্যা।

  1. (ক) vi থেকে vj-তে দৈর্ঘ্য 2-এর walk মানে vi, w, vj, যেখানে w দুজনেরই প্রতিবেশী। i = j হলে w যেকোনো প্রতিবেশী, তাই deg(vi)টি। — পর্ব ১৯-এর walk উপপাদ্য
  2. (খ) কর্ণের যোগফল ∑deg(vi) = 2m. — (ক) আর উপপাদ্য ১.২
  3. (গ) দৈর্ঘ্য 3-এর একটি বদ্ধ walk v, a, b, v নিন। Self-loop নেই বলে a ≠ v, b ≠ a, b ≠ v; তাই v, a, b তিনটি আলাদা vertex, প্রতি জোড়ায় edge: একটি triangle. — simple graph
  4. উল্টো দিকে একটি triangle {x, y, z} থেকে ঠিক 6টি বদ্ধ walk আসে: শুরু ৩টি vertex-এর যেকোনোটি, আর ঘোরার দিক ২টি। তাই trace(A3) = ∑i(A3)ii = 6t. ∎ — গুণের নিয়ম

২ · Incidence matrix — vertex আর edge-এর সম্পর্ক

Adjacency matrix বলে কোন vertex কোন vertex-এর পাশে। অন্য একটি matrix বলে কোন vertex কোন edge-এর প্রান্ত। এটি কম ব্যবহৃত হয়, কিন্তু এর গঠন সুন্দর, আর বৈদ্যুতিক সার্কিট বা network flow-এর সমীকরণ লিখতে এটিই স্বাভাবিক।

সংজ্ঞা ২.১ (incidence matrix)

Loop ছাড়া একটি গ্রাফের incidence matrix হলো n × m matrix B, যেখানে bij = 1 যদি vi edge ej-এর একটি প্রান্ত, নইলে bij = 0. সারি = vertex, কলাম = edge.

উপপাদ্য ২.২ (incidence matrix-এর যোগফল)

Loop নেই এমন যেকোনো গ্রাফে (multigraph-ও চলবে): (ক) B-এর প্রতিটি কলামের যোগফল ঠিক 2; (খ) সারি i-এর যোগফল deg(vi); (গ) তাই ∑deg(v) = 2m.

  1. (ক) কলাম j মানে edge ej. প্রতিটি edge-এর ঠিক দুটি প্রান্ত, আর loop নেই বলে তারা আলাদা দুটি vertex, তাই কলামে ঠিক দুটি 1. — edge-এর সংজ্ঞা, loop নেই
  2. (খ) সারি i-তে 1 ঠিক সেই কলামে, যার edge-এর একটি প্রান্ত vi; তাদের সংখ্যাই deg(vi). Parallel edge থাকলে প্রতিটি আলাদা কলাম, তাই আলাদাভাবে গোনা হয়। — degree-র সংজ্ঞা
  3. (গ) B-এর সব ঘরের যোগফল কলাম ধরে গুনলে 2m, সারি ধরে গুনলে ∑deg(v). ∎ — double counting

Loop থাকলে নিয়ম বদলায়: কিছু বই loop-এর ঘরে 2 লেখে (যাতে কলামের যোগফল তখনও 2 থাকে), কিছু বই 1 লেখে। তাই loop-সহ গ্রাফে কোন রীতি মানা হচ্ছে, তা আগে দেখে নিন। Directed graph-এ সাধারণত oriented incidence matrix নেওয়া হয়: তীর যেখান থেকে বের হয় সেখানে −1, যেখানে ঢোকে সেখানে +1 (কিছু বইয়ে চিহ্ন উল্টো); তখন প্রতিটি কলামের যোগফল 0.

উপপাদ্য ২.৩ (BBT = D + A)

Loop নেই এমন গ্রাফে D হলো degree-গুলোর কর্ণ matrix (dii = deg(vi), বাকি 0). তাহলে BBT = D + A, যেখানে multigraph-এ aij = vi, vj-এর মধ্যের edge-এর সংখ্যা।

  1. (BBT)ik = ∑j bijbkj. পদ bijbkj = 1 ঠিক তখন, যখন vi আর vk দুজনেই ej-এর প্রান্ত। — matrix গুণের সংজ্ঞা
  2. i = k: যোগফল = vi যত edge-এর প্রান্ত = deg(vi). — উপপাদ্য ২.২(খ)
  3. i ≠ k: ej-এর দুই প্রান্তই vi আর vk, অর্থাৎ ej তাদের সংযোগকারী edge; তাই যোগফল = aik. ∎ — প্রতিটি edge-এর ঠিক দুটি প্রান্ত

নিচের stepper একটি ছোট edge list থেকে A আর B একসঙ্গে বানায়। চারটি হাব: ঢাকা (D), গাজীপুর (G), নারায়ণগঞ্জ (N), সাভার (S); রুট e1 = D–G, e2 = D–N, e3 = G–N, e4 = D–S. সারির ক্রম D, G, N, S.

1A = 0 (4×4), B খালি2e1 = {D, G}3e2 = {D, N}4e3 = {G, N}5e4 = {D, S}6যোগফল যাচাই
সারি: D, G, N, S
A
B
deg
  1. শুরু। চারটি vertex, কোনো edge নেই: A একটি 4 × 4 শূন্য matrix, আর B-তে এখনো কোনো কলাম নেই, কারণ প্রতিটি কলাম একটি edge-এর। সব degree 0.
  2. e1 = {D, G}. A-তে দুটি ঘর 1 হয়: সারি D কলাম G, আর সারি G কলাম D. B-তে প্রথম কলাম যোগ হয়, যেখানে D আর G-এর সারিতে 1.
  3. e2 = {D, N}. আবার দুটি প্রতিসম ঘর। B-এর দ্বিতীয় কলাম 1, 0, 1, 0. D-এর degree এখন 2.
  4. e3 = {G, N}. ঘর GN আর NG. লক্ষ করুন, D, G, N এখন একটি triangle; পরে trace(A3) = 6 দেবে।
  5. e4 = {D, S}. S-এর একমাত্র edge. A-এর শেষ সারি 1 0 0 0, আর B-এর শেষ কলাম 1, 0, 0, 1.
  6. যাচাই। A-এর সারির যোগফল 3, 2, 2, 1 = degree; A = AT. B-এর প্রতিটি কলামের যোগফল 2, সারির যোগফল আবার 3, 2, 2, 1. মোট 8 = 2m, যেখানে m = 4.

এবার একটু বড় একটি নেটওয়ার্কে সব দাবি একসঙ্গে পরীক্ষা করি: বাজারঘরের ছয়টি হাব (ঢাকা DHK, গাজীপুর GZP, নারায়ণগঞ্জ NGJ, সাভার SVR, মানিকগঞ্জ MNK, মুন্সিগঞ্জ MSG) আর সাতটি রুট। এখানে নাম শুধু লেবেল, দূরত্ব বা রুট কাল্পনিক। প্রথমবার চালালে ব্রাউজারে Python (Pyodide) নামতে কয়েক সেকেন্ড লাগে; পরের ব্লকগুলো দ্রুত চলে।

hubs = ["DHK", "GZP", "NGJ", "SVR", "MNK", "MSG"]
edges = [("DHK", "GZP"), ("DHK", "NGJ"), ("DHK", "SVR"), ("GZP", "SVR"),
         ("NGJ", "MSG"), ("DHK", "MSG"), ("SVR", "MNK")]
n, m = len(hubs), len(edges)
idx = {h: i for i, h in enumerate(hubs)}
adj = {h: set() for h in hubs}               # adjacency list
A = [[0] * n for _ in range(n)]              # adjacency matrix (n x n)
B = [[0] * m for _ in range(n)]              # incidence matrix (n x m)
for j, (u, v) in enumerate(edges):
    adj[u].add(v); adj[v].add(u)
    A[idx[u]][idx[v]] = A[idx[v]][idx[u]] = 1
    B[idx[u]][j] = B[idx[v]][j] = 1

def mul(X, Y):                               # plain matrix product
    return [[sum(X[i][k] * Y[k][j] for k in range(len(Y)))
             for j in range(len(Y[0]))] for i in range(len(X))]

deg = [len(adj[h]) for h in hubs]
print("list of DHK:", sorted(adj["DHK"]), " degrees:", deg)
print("sum of degrees =", sum(deg), " 2m =", 2 * m)
print("A symmetric:", all(A[i][j] == A[j][i] for i in range(n) for j in range(n)))
print("row sums of A:", [sum(row) for row in A])
print("column sums of B:", [sum(B[i][j] for i in range(n)) for j in range(m)])
BBt = mul(B, [list(col) for col in zip(*B)])
DA = [[deg[i] if i == j else A[i][j] for j in range(n)] for i in range(n)]
print("B times B-transpose == D + A:", BBt == DA)
A2 = mul(A, A); A3 = mul(A2, A)
print("diagonal of A^2:", [A2[i][i] for i in range(n)])
tri = sum(1 for i in range(n) for j in range(i + 1, n) for k in range(j + 1, n)
          if A[i][j] and A[j][k] and A[i][k])
print("trace(A^3) =", sum(A3[i][i] for i in range(n)), " 6 x triangles =", 6 * tri)
print("matrix cells:", n * n, " list entries:", sum(deg), " incidence cells:", n * m)

আসল আউটপুট (ব্রাউজারের Python):

list of DHK: ['GZP', 'MSG', 'NGJ', 'SVR']  degrees: [4, 2, 2, 3, 1, 2]
sum of degrees = 14  2m = 14
A symmetric: True
row sums of A: [4, 2, 2, 3, 1, 2]
column sums of B: [2, 2, 2, 2, 2, 2, 2]
B times B-transpose == D + A: True
diagonal of A^2: [4, 2, 2, 3, 1, 2]
trace(A^3) = 12  6 x triangles = 12
matrix cells: 36  list entries: 14  incidence cells: 42

প্রতিটি লাইন একটি উপপাদ্য: সারির যোগফল আর A2-এর কর্ণ দুটিই degree (উপপাদ্য ১.২, ফল ১.৩(ক)); B-এর সাতটি কলামের প্রতিটিতে 2 (উপপাদ্য ২.২); BBT = D + A (উপপাদ্য ২.৩)। trace(A3) = 12 মানে ঠিক ২টি triangle: DHK–GZP–SVR আর DHK–NGJ–MSG, যা সরাসরি তিন-তিন করে গুনেও মিলেছে। শেষ লাইনটি পরের অনুচ্ছেদের বিষয়: matrix-এ 36টি ঘর, list-এ মাত্র 14টি এন্ট্রি, আর incidence matrix-এ 42টি ঘর।

৩ · কোন representation কখন — জায়গা আর সময়ের হিসাব

তিনটি representation গাণিতিকভাবে সমান (একটি থেকে অন্যটি বানানো যায়), কিন্তু খরচে নয়। n = 6-এ পার্থক্য চোখে পড়ে না; কিন্তু সারা দেশের রাস্তার মোড় নিয়ে গ্রাফ হলে n লাখের ঘরে, আর প্রতিটি মোড়ে গড়ে মাত্র কয়েকটি রাস্তা। এমন গ্রাফ, যেখানে m সম্ভাব্য সর্বোচ্চ C(n, 2)-এর তুলনায় খুব ছোট, তাকে বলে sparse graph; m যদি n2-এর কাছাকাছি হয়, তবে dense graph.

কাজAdjacency matrixAdjacency listIncidence matrix
জায়গাn2টি ঘরn + 2m-এর মাপেরn × m টি ঘর
{u, v} edge কি?এক ঘর দেখা, ধ্রুব সময়N(u) খোঁজা, বড়জোর deg(u) ধাপ (hash set হলে গড়ে ধ্রুব)কলাম খোঁজা, m-এর মাপের
v-এর সব প্রতিবেশীপুরো সারি, n ধাপdeg(v) ধাপসারি আর কলাম, n·m-এর মাপের পর্যন্ত
সব edge একবার করেn2 ধাপn + m ধাপn·m ধাপ
সবচেয়ে উপযোগীdense গ্রাফ, matrix-এর বীজগণিত, ছোট nsparse গ্রাফ, BFS/DFS-এর মতো ঘোরাঘুরিপ্রমাণ, সার্কিট আর flow-এর সমীকরণ

“n + 2m” কোথা থেকে এলো? প্রতিটি vertex-এর একটি তালিকা (n), আর undirected গ্রাফে প্রতিটি edge দুই প্রান্তের তালিকায় একবার করে, মোট ∑deg(v) = 2m এন্ট্রি; এখানেও handshake theorem. ১ লাখ vertex আর ৩ লাখ edge-এর একটি রাস্তার গ্রাফে matrix লাগবে 1010টি ঘর, অথচ list-এ প্রায় ৭ লাখ এন্ট্রি। অন্যদিকে প্রতিটি জোড়ায় edge আছে কি না বারবার জিজ্ঞাসা করতে হয় এমন ছোট dense গ্রাফে matrix-ই দ্রুত। Incidence matrix সবচেয়ে বড় (n × m), তাই এটি সাধারণত হিসাবের জন্য নয়, তত্ত্বের জন্য: যেমন উপপাদ্য ২.৩, বা Kirchhoff-এর সূত্রে সার্কিটের সমীকরণ লেখা।

এই হিসাবগুলো Big-O-এর ভাষায়, আর তাদের প্রোগ্রাম (C++ আর Python-এ গ্রাফ পড়া, CSR-এর মতো সংকুচিত রূপ) DSA কোর্সের পর্ব ৩৯ “গ্রাফ — উপস্থাপন আর পরিভাষা”-এ আছে। এখানে আমরা গণিতে থাকব: কোন representation কোন প্রমাণ সহজ করে। পরের অংশগুলোতে দেখবেন, isomorphism-এর প্রশ্নে adjacency matrix সবচেয়ে কাজের, কারণ “vertex-এর নাম বদলানো” মানে matrix-এর সারি আর কলাম একই ক্রমে সাজানো।

৪ · Isomorphism — একই গ্রাফ, ভিন্ন নাম

একই গ্রাফ দুজন মানুষ দুইভাবে আঁকতে পারেন, আর vertex-গুলোর নামও দিতে পারেন আলাদা। নিচের ছবির বাঁয়ের গ্রাফটি একটি পাঁচ-কোণ, ডানেরটি একটি তারা। দেখতে একেবারে আলাদা, তবু গাণিতিকভাবে এরা একই গ্রাফ। “একই” কথাটির নির্ভুল অর্থ কী?

সংজ্ঞা ৪.১ (graph isomorphism)

দুটি simple graph G = (V, E) আর H = (W, F) isomorphic (লেখা হয় G ≅ H), যদি একটি bijection f : V → W থাকে, যাতে প্রতিটি u, v ∈ V-এর জন্য

{u, v} ∈ E  ⇔  {f(u), f(v)} ∈ F

এমন f-কে বলে একটি isomorphism. অর্থাৎ f edge-কে edge-এ আর non-edge-কে non-edge-এ পাঠায়।

Bijection-এর ধারণা পর্ব ১৬ “ফাংশন — one-to-one, onto, inverse আর composition”-এর। সংজ্ঞায় “⇔” চিহ্নটি জরুরি: শুধু “edge থেকে edge” চাইলে যথেষ্ট নয় (অনুশীলন ৪-এ এর একটি ভুল প্রমাণ আছে)। আর ≅ একটি equivalence relation: identity ফাংশন দেয় reflexive, f-এর inverse দেয় symmetric, আর দুটি isomorphism-এর composition দেয় transitive; তাই সব গ্রাফ “isomorphism শ্রেণি”-তে ভাগ হয়, ঠিক পর্ব ৫৫-এর partition-এর মতো।

একই গ্রাফের দুই ছবি: পাঁচ-কোণ C5 আর তারা

বাঁয়ে edge 1–2, 2–3, 3–4, 4–5, 5–1; ডানে edge a–c, c–e, e–b, b–d, d–a

The 5-cycle drawn as a pentagon and as a pentagram, with the isomorphism 1 to a, 2 to c, 3 to e, 4 to b, 5 to d 12345 abcde G: পাঁচ-কোণH: তারা f: 1→a, 2→c, 3→e, 4→b, 5→d
ছবি ৪.১ — দুটি ছবি দেখতে আলাদা, কিন্তু f প্রতিটি নীল edge-কে একটি সবুজ edge-এ পাঠায়। তারাটির পাশাপাশি বিন্দুগুলো (যেমন a আর b) যুক্ত নয়, একটি বাদ দিয়ে পরেরটির সঙ্গে যুক্ত।

Isomorphic প্রমাণের পথ সরাসরি: একটি f লিখে দিন, তারপর প্রতিটি edge পরীক্ষা করুন। দুটি গ্রাফের edge-সংখ্যা সমান হলে কাজ অর্ধেক: f bijection আর প্রতিটি edge-কে edge-এ পাঠালে, এটি E থেকে F-এ একটি injective ফাংশন দেয়; |E| = |F| বলে সেটি onto-ও, তাই H-এর প্রতিটি edge কোনো edge-এর ছবি, আর non-edge যায় non-edge-এ। নিচের stepper-এ f কীভাবে খুঁজে বের করা হয়, সেটি দেখুন: প্রতিবেশীকে প্রতিবেশীর কাছেই পাঠাতে হবে, এই শর্ত পছন্দগুলো দ্রুত কমিয়ে দেয়।

1n = 5, m = 5, সব deg 22f(1) = a3f(2) ∈ N(a) = {c, d}4f(5) = d5f(3) = e, f(4) = b6৫টি edge যাচাই
G: C₅ → H: তারা
f
বাকি
যাচাই
  1. আগে মিলিয়ে নিন। দুটিতেই ৫টি vertex, ৫টি edge, আর প্রতিটি vertex-এর degree 2. মিল থাকা প্রমাণ নয়, কিন্তু অমিল থাকলে এখানেই থামা যেত।
  2. প্রথম পছন্দ। C5-এর সব vertex একই রকম, তারাটিরও; তাই f(1) = a নেওয়া যায়। এই পছন্দ ভুল হলে পরে অন্যটি চেষ্টা করতাম।
  3. প্রতিবেশী যায় প্রতিবেশীতে। 2 হলো 1-এর প্রতিবেশী, তাই f(2) অবশ্যই a-এর প্রতিবেশী: N(a) = {c, d}. f(2) = c নিই। এখন {1, 2} → {a, c}, একটি edge ✓.
  4. পছন্দ বাধ্য। 1-এর অন্য প্রতিবেশী 5, তাই f(5) হবে a-এর অন্য প্রতিবেশী d. {5, 1} → {d, a} ✓.
  5. পথ ধরে এগোনো। 3 হলো 2-এর অন্য প্রতিবেশী, তাই f(3) = c-এর অন্য প্রতিবেশী e. বাকি থাকে 4 → b. {2, 3} → {c, e} ✓, {3, 4} → {e, b} ✓.
  6. শেষ edge আর সিদ্ধান্ত। {4, 5} → {b, d} ✓. পাঁচটি edge-ই H-এর edge-এ গেছে, f bijection, আর দুই গ্রাফে edge সমান (৫টি), তাই non-edge-ও non-edge-এ যায়। G ≅ H. ∎

Matrix-এর ভাষায় একই কথা: vertex-এর নাম বদলানো মানে A-এর সারি আর কলাম একই permutation-এ সাজানো। f-এর permutation matrix P (প্রতি সারি আর প্রতি কলামে ঠিক একটি 1) নিলে G ≅ H ⇔ কোনো P-এর জন্য PAGPT = AH. শুধু সারি বা শুধু কলাম সাজালে চলবে না; তাতে vertex-এর নাম দুই জায়গায় দুইভাবে বদলায়।

৫ · Invariant — “আলাদা” প্রমাণের হাতিয়ার

দুটি গ্রাফ isomorphic নয়, তা প্রমাণ করা কঠিন শোনায়: n! টি bijection-এর একটিও কাজ করে না, তা দেখাতে হবে। কিন্তু একটি চতুর পথ আছে: এমন কোনো সংখ্যা বা ধর্ম খুঁজুন, যা isomorphism-এ বদলায় না, অথচ দুটি গ্রাফে আলাদা।

সংজ্ঞা ৫.১ (graph invariant)

একটি graph invariant হলো গ্রাফের এমন একটি ধর্ম বা সংখ্যা, যা প্রতিটি জোড়া isomorphic গ্রাফে একই। তাই কোনো invariant দুটি গ্রাফে আলাদা হলে তারা isomorphic নয়; এটি contrapositive যুক্তি।

উপপাদ্য ৫.২ (মৌলিক invariant)

G ≅ H হলে দুটির (ক) vertex-সংখ্যা আর edge-সংখ্যা সমান; (খ) degree sequence (degree-গুলো বড় থেকে ছোট সাজানো তালিকা) সমান; (গ) triangle-এর সংখ্যা সমান; (ঘ) প্রতিটি k-এর জন্য দৈর্ঘ্য k-এর cycle-এর সংখ্যা সমান; (ঙ) একটি connected হলে অন্যটিও; (চ) একটি bipartite হলে অন্যটিও।

ধরুন f : V → W একটি isomorphism.

  1. (ক) f bijection, তাই |V| = |W|. f edge আর non-edge ঠিক রাখে, তাই e = {u, v} ↦ {f(u), f(v)} হলো E থেকে F-এ একটি bijection (উল্টোটি f−1 দিয়ে), আর |E| = |F|. — সংজ্ঞা ৪.১
  2. (খ) যেকোনো v-এর জন্য u ∈ N(v) ⇔ f(u) ∈ N(f(v)), তাই f, N(v)-কে N(f(v))-এর ওপর bijection-এ পাঠায়, আর deg(v) = deg(f(v)). f সব vertex-কে এক-এক মেলায়, তাই degree-গুলোর বহুসেট একই, অর্থাৎ degree sequence সমান। — isomorphism প্রতিবেশী ঠিক রাখে
  3. (গ) {x, y, z} triangle ⇔ তিনটি জোড়াই edge ⇔ {f(x), f(y)}, {f(y), f(z)}, {f(x), f(z)} তিনটিই edge ⇔ {f(x), f(y), f(z)} triangle. তাই f, G-এর triangle-গুলোকে H-এর triangle-গুলোর ওপর bijection-এ পাঠায়। — সংজ্ঞা ৪.১, তিনবার
  4. (ঘ) একই যুক্তি: একটি k-cycle-এর পরপর vertex-গুলোর ছবি পরপর যুক্ত, আর f injective বলে তারা আলাদা থাকে। — ধাপ ৩-এর সাধারণ রূপ
  5. (ঙ, চ) G-এ u থেকে v-এর একটি path-এর ছবি H-এ f(u) থেকে f(v)-এর path; আর G-এর একটি দুই-রঙ করা (bipartite ভাগ) V = X ∪ Y থেকে W = f(X) ∪ f(Y) একটি দুই-রঙ করা দেয়। উল্টো দিক f−1 দিয়ে। ∎ — প্রতিবেশী ঠিক থাকে

লক্ষ করুন, “vertex 1-এর degree 3” কোনো invariant নয়: নামটি f বদলে দেয়। Invariant হতে হলে ধর্মটি নামের ওপর নির্ভর করতে পারবে না। এবার দুটি পরিচিত জোড়া দেখি, যাদের প্রথম দুটি invariant মেলে।

  • C6 বনাম দুটি আলাদা triangle (2C3): দুটিতেই ৬টি vertex, ৬টি edge, সব degree 2. কিন্তু C6 connected আর তাতে triangle নেই; 2C3 connected নয়, triangle ২টি। Isomorphic নয়।
  • প্রিজম বনাম K3,3: দুটিই connected, ৬টি vertex, ৯টি edge, সব degree 3. এখানে connectedness-ও মেলে; পার্থক্য ধরা পড়ে triangle-এ, নিচের ছবি আর stepper-এ।

একই degree sequence, ভিন্ন গ্রাফ: প্রিজম আর K3,3

দুটিতেই ৬টি vertex, ৯টি edge, প্রতিটি vertex-এর degree 3

The triangular prism with two shaded triangles next to the complete bipartite graph K3,3, which has no triangle 123 456 abc xyz G: প্রিজমH: K3,3 triangle ২টিtriangle ০টি
ছবি ৫.১ — প্রিজমে হলুদ দুটি triangle: {1, 2, 3} আর {4, 5, 6}. K3,3-এ প্রতিটি edge ওপরের সারি থেকে নিচের সারিতে যায়, তাই তিনটি vertex-এর দুটি একই সারিতে পড়বেই, আর তাদের মধ্যে edge নেই।
1n: 6 বনাম 62m: 9 বনাম 93degree sequence4connected?5triangle গোনা6trace(A³) দিয়ে যাচাই
G = প্রিজম, H = K₃,₃
G
H
ফল
  1. Vertex-সংখ্যা। দুটিতেই ৬টি। এই invariant কিছু আলাদা করে না।
  2. Edge-সংখ্যা। প্রিজমে দুটি triangle-এর ৩ + ৩টি আর তিনটি স্পোক, মোট ৯; K3,3-এ 3 × 3 = ৯. মেলে।
  3. Degree sequence. প্রিজমে প্রতিটি vertex নিজের triangle-এর দুজন আর একটি স্পোকের সঙ্গে যুক্ত: degree 3. K3,3-এ প্রত্যেকে অন্য সারির তিনজনের সঙ্গে: degree 3. দুটিই 3-regular.
  4. Connectedness. দুটিই connected. চারটি সহজ invariant মিলে গেল, অথচ উত্তর এখনো অজানা।
  5. Triangle. প্রিজমে ঠিক ২টি triangle. K3,3-এ যেকোনো তিনটি vertex-এর দুটি একই সারিতে, আর একই সারিতে edge নেই: triangle ০টি। উপপাদ্য ৫.২(গ) অনুযায়ী G ≇ H.
  6. Matrix দিয়ে যাচাই। ফল ১.৩(গ): trace(AG3) = 12 = 6 × 2 আর trace(AH3) = 0. দুটি স্বাধীন হিসাব একই কথা বলে। (আরেকটি অমিল invariant: K3,3 bipartite, প্রিজম নয়, কারণ triangle একটি বিজোড় cycle.)

সাবধান: invariant শুধু একদিকে কাজ করে। “সব invariant মিলেছে, তাই isomorphic” যুক্তিটি ভুল, যদি না আপনি প্রমাণ করেন যে আপনার invariant-এর তালিকা complete, অর্থাৎ শ্রেণিটি পুরোপুরি চিনিয়ে দেয়। এমন দ্রুত গণনাযোগ্য complete invariant জানা নেই। একটি উদাহরণ: adjacency matrix-এর eigenvalue-গুলো (eigenvalue, “spectrum”) একটি invariant, কারণ PAPT-এর eigenvalue আর A-এর eigenvalue এক। কিন্তু তারা K1,4 (একটি কেন্দ্র আর চারটি পাতা) আর C4 ∪ K1 (একটি চতুর্ভুজ আর একটি একা vertex)-এ হুবহু এক: দুটির characteristic polynomial-ই x5 − 4x3 (scratch-এ হিসাব করে মেলানো)। অথচ একটি connected, অন্যটি নয়। এমন জোড়াকে বলে cospectral.

৬ · যন্ত্রে isomorphism পরীক্ষা — brute force, pruning আর জটিলতা

সংজ্ঞাটিই একটি algorithm দেয়: V থেকে W-এ সব n! টি bijection একে একে নিন, আর প্রতিটির জন্য সব জোড়া পরীক্ষা করুন। n = 10-এ 10! = 3,628,800 টি bijection, n = 20-এ প্রায় 2.4 × 1018. তাই দুটি সহজ বুদ্ধি লাগে, ঠিক §৪-এর stepper-এর মতো: (১) degree না মিললে সেই vertex-এ পাঠানোই যাবে না; (২) একটি একটি করে vertex বসান, আর প্রতিবার আগে বসানো সবার সঙ্গে edge/non-edge মিলছে কি না দেখুন; না মিললে সেই শাখা সেখানেই বাদ (backtracking, পর্ব ৩৬)। নিচের ব্লক দুটি পদ্ধতিই তিনটি জোড়ায় চালায়: C5 বনাম তারা, প্রিজম বনাম K3,3, আর একটি ঘনক (Q3) বনাম তার এলোমেলো নামের আরেকটি কপি।

from itertools import permutations
def graph(text):                       # "a-b b-c ..." -> adjacency sets
    G = {}
    for u, v in (e.split("-") for e in text.split()):
        G.setdefault(u, set()).add(v); G.setdefault(v, set()).add(u)
    return G
def brute(G, H):                       # try all n! bijections in order
    for tried, img in enumerate(permutations(sorted(H)), 1):
        f = dict(zip(sorted(G), img))
        if all((f[v] in H[f[u]]) == (v in G[u]) for u in G for v in G):
            return True, tried
    return False, tried
def pruned(G, H, f, calls):            # backtracking: degree + edges so far
    calls[0] += 1
    if len(f) == len(G):
        return True
    u = sorted(G)[len(f)]
    for x in sorted(set(H) - set(f.values())):
        if len(H[x]) == len(G[u]) and \
           all((f[w] in H[x]) == (w in G[u]) for w in f):
            f[u] = x
            if pruned(G, H, f, calls): return True
            del f[u]
    return False

pairs = {"C5 vs star": ("1-2 2-3 3-4 4-5 5-1", "a-c c-e e-b b-d d-a"),
         "prism vs K33": ("1-2 2-3 3-1 4-5 5-6 6-4 1-4 2-5 3-6",
                          "a-x a-y a-z b-x b-y b-z c-x c-y c-z"),
         "cube vs cube": ("1-2 2-3 3-4 4-1 5-6 6-7 7-8 8-5 1-5 2-6 3-7 4-8",
                          "a-h a-c a-e h-b h-g c-b c-d e-g e-d b-f g-f d-f")}
for name, (g, h) in pairs.items():
    G, H, f, calls = graph(g), graph(h), {}, [0]
    (ok, tried), found = brute(G, H), pruned(G, H, f, calls)
    print(f"{name}: isomorphic={ok}, brute tried {tried}, pruned calls {calls[0]}")
    if found: print("   f =", f)

আসল আউটপুট (ব্রাউজারের Python):

C5 vs star: isomorphic=True, brute tried 11, pruned calls 6
   f = {'1': 'a', '2': 'c', '3': 'e', '4': 'b', '5': 'd'}
prism vs K33: isomorphic=False, brute tried 720, pruned calls 25
cube vs cube: isomorphic=True, brute tried 823, pruned calls 9
   f = {'1': 'a', '2': 'c', '3': 'b', '4': 'h', '5': 'e', '6': 'd', '7': 'f', '8': 'g'}

C5-এর জন্য backtracking §৪-এর stepper-এর ঠিক সেই f খুঁজে পেয়েছে। প্রিজম বনাম K3,3-এ brute force-কে সব 6! = 720টি bijection দেখতে হয়েছে, কারণ “না” বলতে হলে সবগুলো বাতিল করতে হয়; backtracking মাত্র ২৫টি ডাকেই শেষ, কারণ প্রথম triangle-এর তৃতীয় vertex বসানোর আগেই প্রতিটি শাখা ভেঙে পড়ে। ঘনকের ক্ষেত্রে brute force 8! = 40320-এর মধ্যে ৮২৩তমটিতে ভাগ্যক্রমে উত্তর পেয়েছে; ভাগ্য না থাকলে পুরো 40320. Degree এখানে কিছুই ছাঁটে না (সব degree সমান), তবু edge-পরীক্ষাই বেশিরভাগ শাখা কেটে দেয়।

জটিলতা: সমস্যাটি কতটা কঠিন?

Pruning ছোট গ্রাফে দারুণ কাজ করে, কিন্তু সবচেয়ে খারাপ ক্ষেত্রে এটিও exponential হতে পারে, বিশেষ করে খুব প্রতিসম (যেমন regular) গ্রাফে, যেখানে degree কোনো তথ্য দেয় না। Graph isomorphism (GI) সমস্যাটি জটিলতা-তত্ত্বে একটি অদ্ভুত জায়গায় আছে। এটি NP-তে আছে, কারণ একটি f দিলে তা polynomial সময়ে যাচাই করা যায় (DSA কোর্সের পর্ব ৬৪ “P বনাম NP — NP-complete আর reduction” দেখুন)। কিন্তু এটি NP-complete বলে প্রমাণিত নয়, আর polynomial সময়ের কোনো algorithm-ও জানা নেই। László Babai ২০১৫ সালে একটি quasi-polynomial সময়ের algorithm ঘোষণা করেন, অর্থাৎ সময় exp((log n)c)-এর মতো, যা polynomial-এর চেয়ে সামান্য বেশি কিন্তু exponential-এর চেয়ে অনেক কম; ২০১৭ সালের শুরুতে বিশ্লেষণে একটি ত্রুটি ধরা পড়লে তিনি তা সংশোধন করেন বলে জানা যায়। পর্ব ৫১-এর প্র ০৪-এ এর প্রেক্ষাপট আছে: শ্রেণি গোনা সহজ, কিন্তু দুটি নির্দিষ্ট গ্রাফ একই শ্রেণিতে কি না, সেই সিদ্ধান্ত কঠিনতর।

৭ · Automorphism আর লেবেলযুক্ত বনাম লেবেলহীন গ্রাফ

§৪-এর stepper-এ f(1) = a নেওয়ার সময় বলা হয়েছিল “C5-এর সব vertex একই রকম”। এই কথার নির্ভুল রূপ হলো symmetry: গ্রাফকে নিজের ওপর এমনভাবে সাজানো, যাতে edge-গুলো edge-ই থাকে।

সংজ্ঞা ৭.১ (automorphism)

G থেকে G-তেই একটি isomorphism σ : V → V-কে বলে G-এর একটি automorphism. G-এর সব automorphism-এর সেট Aut(G) composition-এর অধীনে একটি group: identity এতে আছে, দুটির composition আবার automorphism, আর প্রতিটির inverse-ও automorphism.

উদাহরণ: Kn-এর প্রতিটি permutation একটি automorphism, তাই |Aut(Kn)| = n!. একা n টি vertex (কোনো edge নেই)-এরও n!. K3,3-এ একটি সারির ভেতরে 3! রকম সাজানো, অন্য সারিতেও 3!, আর দুই সারি অদলবদল 2 রকম: 2 · 3! · 3! = 72. প্রিজমে 12. (শেষ দুটি সংখ্যা scratch-এ সব 720টি permutation পরীক্ষা করে মেলানো।)

উপপাদ্য ৭.২

|Aut(C5)| = 10. সাধারণভাবে n ≥ 3 হলে |Aut(Cn)| = 2n.

Cn-এর vertex 1, 2, …, n, আর edge {i, i + 1}, যেখানে n + 1 মানে 1 ধরা হয়।

  1. বড়জোর 2n: σ(1) বাছার n উপায়। 2 হলো 1-এর প্রতিবেশী, তাই σ(2) অবশ্যই σ(1)-এর দুই প্রতিবেশীর একটি: 2 উপায়। — automorphism প্রতিবেশী ঠিক রাখে
  2. এরপর সব বাধ্য: 3 হলো 2-এর 1 ছাড়া অন্য প্রতিবেশী, তাই σ(3) = σ(2)-এর σ(1) ছাড়া অন্য প্রতিবেশী; একইভাবে σ(4), …, σ(n). তাই σ(1) আর σ(2) পুরো σ ঠিক করে দেয়। — cycle ধরে induction
  3. অন্তত 2n: n টি rotation (i ↦ i + k) আর n টি reflection (i ↦ k − i), সব mod n, প্রতিটি edge {i, i + 1}-কে edge-এ পাঠায়, আর এই 2n টি ফাংশন আলাদা (σ(1), σ(2) জোড়া সবার আলাদা)। — সরাসরি যাচাই
  4. তাই |Aut(Cn)| = 2n, আর n = 5-এ 10. ∎ এটিই পর্ব ৫১-এর dihedral group.

এবার গণনার প্রশ্ন। {1, 2, 3, 4, 5}-এর ওপর কয়টি আলাদা লেবেলযুক্ত গ্রাফ C5-এর isomorphic, অর্থাৎ পাঁচটি নামকে একটি বৃত্তে সাজানোর কয়টি আলাদা উপায়ে আলাদা edge-সেট আসে? সব 5! = 120 সাজানো চেষ্টা করলে একই edge-সেট বারবার আসে; ঠিক কতবার, তা বলে automorphism.

উপপাদ্য ৭.৩ (লেবেলযুক্ত কপির সংখ্যা)

G-এর vertex সেট V, |V| = n. V-এর ওপর G-এর isomorphic এমন আলাদা গ্রাফ (edge-সেট) ঠিক n!/|Aut(G)|টি।

  1. V-এর প্রতিটি permutation σ থেকে একটি গ্রাফ σ(G) পাই, যার edge-সেট {{σ(u), σ(v)} : {u, v} ∈ E}; σ নিজেই G থেকে σ(G)-তে isomorphism. — সংজ্ঞা ৪.১
  2. V-এর ওপর G ≅ H হলে, তার isomorphism f : V → V নিজেই একটি permutation আর H = f(G). তাই প্রতিটি কপি কোনো σ থেকে আসে। — onto
  3. σ(G) = τ(G) ⇔ τ−1σ(G) = G ⇔ τ−1σ ∈ Aut(G) ⇔ σ ∈ τ·Aut(G). তাই একটি নির্দিষ্ট কপি τ(G) ঠিক |Aut(G)|টি permutation থেকে আসে। — group-এর সংজ্ঞা
  4. n! টি permutation সমান মাপের (|Aut(G)|টি করে) দলে ভাগ হয়, প্রতিটি দল একটি কপি; কপি n!/|Aut(G)|টি। ∎ — ভাগের নিয়ম

এটি আসলে পর্ব ৫১-এর orbit–stabilizer উপপাদ্য: permutation-গুলো লেবেলযুক্ত গ্রাফের ওপর কাজ করে, G-এর orbit হলো তার সব কপি, আর stabilizer হলো Aut(G). C5-এর ক্ষেত্রে 120/10 = 12টি লেবেলযুক্ত কপি; হাতে দেখুন: 1-কে স্থির রেখে বাকি চারটিকে বৃত্তে 4! = 24 ভাবে সাজানো যায়, আর প্রতিটি বৃত্ত দুই দিক থেকে পড়া যায়, 24/2 = 12. এখান থেকে একটি দরকারি সূত্র: n-vertex-এর লেবেলযুক্ত গ্রাফ মোট 2C(n,2)টি (প্রতিটি জোড়ায় edge আছে বা নেই), আর লেবেলহীন গ্রাফ, অর্থাৎ isomorphism শ্রেণি, গুনতে হলে প্রতিটি শ্রেণির জন্য উপপাদ্য ৭.৩ বসিয়ে

∑শ্রেণি G n!/|Aut(G)| = 2C(n,2)

যাচাই করতে হবে। পরের অংশের Python ব্লক n = 4-এ এটিই করে।

৮ · Canonical form — প্রতিটি শ্রেণির একটি প্রতিনিধি

লাখ লাখ গ্রাফের একটি ডেটাবেসে নতুন গ্রাফ এলে প্রশ্ন: এটি কি আগে থেকেই আছে, শুধু অন্য নামে? প্রতিবার সবার সঙ্গে isomorphism পরীক্ষা অসম্ভব। ভালো উপায় হলো প্রতিটি গ্রাফকে একটি নির্দিষ্ট “আদর্শ নাম”-এ রূপান্তর করা, যাতে দুটি গ্রাফ isomorphic হলে এবং কেবল তখনই তাদের আদর্শ নাম এক হয়। তখন ডেটাবেসে শুধু সেই নাম খুঁজলেই চলে, যেমন অভিধানে শব্দ খোঁজা।

সংজ্ঞা ও উপপাদ্য ৮.১ (brute-force canonical form)

V = {0, 1, …, n − 1}-এর ওপর গ্রাফ G-এর জন্য, প্রতিটি permutation σ-এর পরে adjacency matrix-এর ওপরের ত্রিভুজের ঘরগুলো (জোড়া (0,1), (0,2), …, (n−2, n−1) ক্রমে) পাশাপাশি লিখে একটি 0-1 string s(σ(G)) পাই। সংজ্ঞা: canon(G) = সব σ-এর মধ্যে অভিধান-ক্রমে সবচেয়ে ছোট s(σ(G)). তাহলে G ≅ H ⇔ canon(G) = canon(H).

  1. (⇒) G ≅ H হলে H = f(G) কোনো permutation f-এর জন্য (উপপাদ্য ৭.৩-এর ধাপ ২)। তাহলে {σ(H)} = {σf(G)} = {τ(G)}: permutation-গুলোর সেট একই, কারণ σ ↦ σf একটি bijection. একই string-সেটের সর্বনিম্ন একই। — group-এ গুণ bijection
  2. (⇐) canon(G) = canon(H) = s হলে কোনো σ, τ-এর জন্য s(σ(G)) = s(τ(H)). String গ্রাফটিকে পুরো নির্ধারণ করে, তাই σ(G) = τ(H), আর G ≅ σ(G) = τ(H) ≅ H. ∎ — ≅ transitive

এটি canonical form-এর সবচেয়ে সরল রূপ। খরচ n! × C(n, 2), তাই শুধু ছোট n-এ চলে; বাস্তবের সফটওয়্যার একই ধারণা অনেক বুদ্ধি খাটিয়ে প্রয়োগ করে (প্র ০১)। নিচের ব্লক ৪টি vertex-এর সব 26 = 64টি লেবেলযুক্ত গ্রাফের canonical form বের করে, শ্রেণিতে ভাগ করে, প্রতিটি শ্রেণির |Aut| গোনে, আর §৭-এর সূত্র যাচাই করে।

from itertools import combinations, permutations, product
from collections import defaultdict
from math import factorial

n = 4
pairs = list(combinations(range(n), 2))     # the 6 possible edges
perms = list(permutations(range(n)))        # the 24 relabellings

def code(E, p):                             # adjacency string after relabelling p
    F = {frozenset((p[u], p[v])) for u, v in E}
    return "".join("1" if frozenset(q) in F else "0" for q in pairs)

classes = defaultdict(list)
for bits in product((0, 1), repeat=len(pairs)):
    E = [q for q, b in zip(pairs, bits) if b]
    canon = min(code(E, p) for p in perms)  # canonical form = smallest string
    classes[canon].append(E)

print("labelled graphs:", sum(map(len, classes.values())),
      " isomorphism classes:", len(classes))
total = 0
for canon in sorted(classes, key=lambda c: (c.count("1"), c)):
    E = classes[canon][0]
    own = code(E, range(n))
    aut = sum(code(E, p) == own for p in perms)   # automorphisms of E
    size = len(classes[canon])
    total += factorial(n) // aut
    print(f"{canon}  m={canon.count('1')}  labelled={size:2}"
          f"  |Aut|={aut:2}  4!/|Aut|={factorial(n) // aut:2}")
print("sum of 4!/|Aut| over classes =", total)

আসল আউটপুট (ব্রাউজারের Python):

labelled graphs: 64  isomorphism classes: 11
000000  m=0  labelled= 1  |Aut|=24  4!/|Aut|= 1
000001  m=1  labelled= 6  |Aut|= 4  4!/|Aut|= 6
000011  m=2  labelled=12  |Aut|= 2  4!/|Aut|=12
001100  m=2  labelled= 3  |Aut|= 8  4!/|Aut|= 3
000111  m=3  labelled= 4  |Aut|= 6  4!/|Aut|= 4
001011  m=3  labelled= 4  |Aut|= 6  4!/|Aut|= 4
001101  m=3  labelled=12  |Aut|= 2  4!/|Aut|=12
001111  m=4  labelled=12  |Aut|= 2  4!/|Aut|=12
011110  m=4  labelled= 3  |Aut|= 8  4!/|Aut|= 3
011111  m=5  labelled= 6  |Aut|= 4  4!/|Aut|= 6
111111  m=6  labelled= 1  |Aut|=24  4!/|Aut|= 1
sum of 4!/|Aut| over classes = 64

৬৪টি লেবেলযুক্ত গ্রাফ ১১টি শ্রেণিতে পড়ে, ঠিক পর্ব ৫১-এ Burnside দিয়ে পাওয়া সংখ্যা। প্রতিটি সারিতে “labelled” কলাম (সরাসরি গোনা) আর “4!/|Aut|” কলাম (উপপাদ্য ৭.৩) হুবহু মেলে, আর যোগফল 64 = 26. String পড়তে জোড়ার ক্রম মনে রাখুন: (0,1), (0,2), (0,3), (1,2), (1,3), (2,3). যেমন 000111 মানে edge {1,2}, {1,3}, {2,3}: একটি triangle আর একা vertex 0; 001011 মানে {0,3}, {1,3}, {2,3}: 3-কে কেন্দ্র করে একটি তারা; 011110 হলো C4, যার |Aut| = 8 = 2 · 4 (উপপাদ্য ৭.২)। ৩টি edge-এর তিনটি শ্রেণি (triangle + একা, তারা, path) মিলে 4 + 4 + 12 = 20 = C(6, 3)টি লেবেলযুক্ত গ্রাফ।

৯ · Petersen graph, পরীক্ষার অঙ্ক আর একটি ভুল প্রমাণ

গ্রাফ তত্ত্বে একটি গ্রাফ এত বেশি অনুমানের পাল্টা-উদাহরণ যে তাকে প্রায় সব বইয়ে পাওয়া যায়: Petersen graph. এর সবচেয়ে পরিষ্কার সংজ্ঞা সেট দিয়ে: vertex হলো {1, 2, 3, 4, 5}-এর দশটি দুই-উপাদানের subset, আর দুটি subset-এর মধ্যে edge ঠিক তখন, যখন তারা বিচ্ছিন্ন (কোনো সাধারণ উপাদান নেই)। এই ধাঁচের গ্রাফকে বলে Kneser graph K(5, 2). ছবিতে এটি সাধারণত একটি বাইরের পাঁচ-কোণ আর ভেতরের তারা হিসেবে আঁকা হয়।

Petersen graph: “12” মানে subset {1, 2}

বাইরে পাঁচ-কোণ, ভেতরে তারা, আর পাঁচটি স্পোক; প্রতিটি edge দুটি বিচ্ছিন্ন subset-কে জোড়ে

The Petersen graph drawn as an outer pentagon and inner pentagram, vertices labelled by 2-subsets of 1 to 5 1234152345 3525241413
ছবি ৯.১ — নীল পাঁচ-কোণ, সবুজ তারা আর কমলা স্পোক মিলে ১৫টি edge. যেমন 12-এর প্রতিবেশী 34, 45 আর 35: ঠিক সেই তিনটি subset, যাতে 1 বা 2 নেই।
উপপাদ্য ৯.১ (Petersen graph-এর ধর্ম)

(ক) 10টি vertex, 15টি edge, 3-regular. (খ) কোনো triangle বা 4-cycle নেই, তাই সবচেয়ে ছোট cycle-এর দৈর্ঘ্য (girth) 5. (গ) যেকোনো দুটি vertex-এর দূরত্ব বড়জোর 2 (diameter 2). (ঘ) |Aut| ≥ 120.

  1. (ক) C(5, 2) = 10. একটি subset {a, b}-এর সঙ্গে বিচ্ছিন্ন subset বাকি তিনটি উপাদান থেকে নিতে হয়: C(3, 2) = 3, তাই 3-regular; handshake থেকে m = 10 · 3/2 = 15. — গণনা
  2. (খ) Triangle মানে তিনটি পরস্পর বিচ্ছিন্ন দুই-উপাদানের subset, যাদের মোট 6টি আলাদা উপাদান লাগে; কিন্তু আছে মাত্র 5টি। — pigeonhole
  3. 4-cycle x, y, z, w ধরুন। x আর z দুজনেই y আর w-এর সঙ্গে বিচ্ছিন্ন, অর্থাৎ x, z ⊆ {1,…,5} − (y ∪ w). y ≠ w বলে |y ∪ w| ≥ 3, তাই বাকি থাকে বড়জোর 2টি উপাদান, আর x = z হতে বাধ্য; কিন্তু cycle-এ x ≠ z. বিরোধ। — proof by contradiction
  4. (গ) দুটি আলাদা, যুক্ত নয় এমন vertex মানে দুটি subset, যাদের ঠিক একটি উপাদান সাধারণ, যেমন {1, 2} আর {1, 3}. তাদের union-এ 3টি উপাদান, বাকি দুটি (এখানে {4, 5}) দুজনের সঙ্গেই বিচ্ছিন্ন: একটি সাধারণ প্রতিবেশী। দূরত্ব 2. — সরাসরি নির্মাণ
  5. (ঘ) {1,…,5}-এর যেকোনো permutation π subset-গুলোকে subset-এ পাঠায় আর বিচ্ছিন্নতা ঠিক রাখে (π injective), তাই প্রতিটি π একটি automorphism দেয়; আলাদা π আলাদা automorphism দেয়। মোট অন্তত 5! = 120. ∎ — বিচ্ছিন্নতা নামের ওপর নির্ভর করে না

আসলে |Aut| ঠিক 120; উপরের সীমা প্রমাণে আরও কাজ লাগে, তাই এখানে brute-force backtracking দিয়ে গুনে দেখি। একই ব্লক girth আর diameter-ও সরাসরি যাচাই করে।

from itertools import combinations
from collections import deque
from math import factorial

V = [frozenset(s) for s in combinations(range(1, 6), 2)]  # 2-subsets of {1..5}
P = {v: {w for w in V if not v & w} for v in V}           # edge iff disjoint
n, m = len(V), sum(len(P[v]) for v in V) // 2
print("n =", n, " m =", m, " degrees:", sorted({len(P[v]) for v in V}))

def dist(s):                                 # BFS distances from s
    d, q = {s: 0}, deque([s])
    while q:
        u = q.popleft()
        for w in P[u] - d.keys():
            d[w] = d[u] + 1; q.append(w)
    return d
print("diameter =", max(max(dist(v).values()) for v in V))
tri = sum(1 for a, b, c in combinations(V, 3)
          if b in P[a] and c in P[a] and c in P[b])
quad = sum(1 for a, b, c, d in combinations(V, 4)
           for w, x, y, z in [(a, b, c, d), (a, b, d, c), (a, c, b, d)]
           if x in P[w] and y in P[x] and z in P[y] and w in P[z])
print("triangles =", tri, " 4-cycles =", quad, " so girth = 5")

def count(f):                                # extend partial automorphism f
    if len(f) == n:
        return 1
    u, total = V[len(f)], 0
    for x in V:
        if x not in f.values() and all((f[w] in P[x]) == (w in P[u]) for w in f):
            f[u] = x; total += count(f); del f[u]
    return total
aut = count({})
print("|Aut| =", aut, " labelled copies 10!/|Aut| =", factorial(10) // aut)

আসল আউটপুট (ব্রাউজারের Python):

n = 10  m = 15  degrees: [3]
diameter = 2
triangles = 0  4-cycles = 0  so girth = 5
|Aut| = 120  labelled copies 10!/|Aut| = 30240

উপপাদ্য ৯.১-এর প্রতিটি অংশ মিলেছে, আর |Aut| ঠিক 120, অর্থাৎ Petersen graph-এর প্রতিটি symmetry {1,…,5}-এর কোনো permutation থেকে আসে। Backtracking ব্যবহার না করে সব 10! = 3,628,800টি permutation পরীক্ষা করলে ব্রাউজারে অনেক বেশি সময় লাগত। উপপাদ্য ৭.৩ অনুযায়ী দশটি নির্দিষ্ট লেবেলের ওপর Petersen graph-এর আলাদা কপি 10!/120 = 30240টি। 4-cycle গোনার লাইনে প্রতিটি চারটি vertex-এর সেটকে তিনটি সম্ভাব্য বৃত্তাকার ক্রমে পরীক্ষা করা হয়েছে।

আরও কয়েকটি ধর্ম, যেগুলোর প্রমাণ পরের পর্বগুলোর বিষয় (scratch-এ brute force দিয়ে মেলানো): Petersen graph-এ কোনো Hamilton cycle নেই (পর্ব ৬০ “Euler আর Hamilton path — Königsberg থেকে NP-কঠিনতা”), এটি planar নয় (পর্ব ৬২ “Planar graph — Euler-এর সূত্র আর Kuratowski”), এর chromatic number 3, কিন্তু edge-গুলোকে ৩ রঙে এমনভাবে রাঙানো যায় না যাতে একই vertex-এ দুটি edge একই রঙের হয় (পর্ব ৬৩ “Graph coloring — chromatic number, scheduling আর চার রঙের উপপাদ্য”)। 5-cycle আছে বলে এটি bipartite-ও নয়।

অঙ্ক ১: Matrix থেকে তথ্য পড়া

একটি simple graph-এর vertex v1, …, v5 আর edge v1v2, v1v3, v2v3, v3v4, v4v5. (ক) incidence matrix-এর মাপ আর সব ঘরের যোগফল কত? (খ) (A2)14 আর (A2)33 কত? (গ) trace(A3) কত?

  1. (ক) n = 5, m = 5, তাই B একটি 5 × 5 matrix; সব ঘরের যোগফল 2m = 10 (উপপাদ্য ২.২)।
  2. (খ) (A2)14 = v1 আর v4-এর সাধারণ প্রতিবেশী: শুধু v3, তাই 1. (A2)33 = deg(v3) = 3.
  3. (গ) Triangle শুধু {v1, v2, v3}, তাই trace(A3) = 6 × 1 = 6 (scratch-এ matrix গুণ করে মেলানো)।

অঙ্ক ২: লেবেলযুক্ত গ্রাফ গোনা

{1, 2, 3, 4}-এর ওপর ঠিক ৩টি edge-যুক্ত লেবেলযুক্ত গ্রাফ কয়টি, আর তারা কয়টি isomorphism শ্রেণিতে পড়ে? উত্তর: C(6, 3) = 20টি, ৩টি শ্রেণিতে। Triangle + একা vertex: |Aut| = 3! = 6, কপি 24/6 = 4 (একা vertex বাছার ৪ উপায়)। তারা K1,3: |Aut| = 6, কপি 4 (কেন্দ্র বাছার ৪ উপায়)। Path P4: |Aut| = 2 (উল্টে পড়া), কপি 12. যোগফল 4 + 4 + 12 = 20 ✓ (canonical form ব্লকের m = 3 সারিগুলো)।

প্রমাণের ভুল ধরুন: “সব invariant মিলেছে”

একজন লিখলেন: “দুটি গ্রাফে vertex ৬টি, edge ৯টি, degree sequence (3, 3, 3, 3, 3, 3), আর দুটিই connected. isomorphism এই সব ধর্ম রক্ষা করে, তাই গ্রাফ দুটি isomorphic হবেই।”

ভুল কোথায়: উপপাদ্য ৫.২ বলে “isomorphic ⇒ invariant সমান”; লেখক ব্যবহার করেছেন উল্টো দিক “invariant সমান ⇒ isomorphic”, যা প্রমাণিত নয়, আর এখানে মিথ্যা: প্রিজম আর K3,3 ঠিক এই সব ধর্ম মেনে চলে, তবু isomorphic নয়, যা §৫-এর stepper-এ দেখা গেছে। এটি পর্ব ৮-এর converse-এর ভুল। Isomorphic প্রমাণের একমাত্র নিরাপদ পথ একটি স্পষ্ট bijection দেখানো (বা একটি complete invariant, যেমন canonical form, মেলানো)।

আরও গভীরে: গ্রাফ চেনার জনপ্রিয় একটি দ্রুত কৌশল colour refinement (১-মাত্রার Weisfeiler–Leman): শুরুতে সব vertex এক রঙ, তারপর বারবার প্রতিটি vertex-কে তার প্রতিবেশীদের রঙের বহুসেট অনুযায়ী নতুন রঙ দেওয়া। দুই গ্রাফে রঙের হিসাব আলাদা হলে তারা isomorphic নয়; কিন্তু একই degree-র regular গ্রাফে প্রথম ধাপেই সব রঙ স্থির হয়ে যায়, তাই প্রিজম আর K3,3-কে এই কৌশল আলাদা করতে পারে না। Babai-এর quasi-polynomial algorithm-এর একটি অংশ এই refinement-এর উচ্চতর রূপ আর group তত্ত্বের মিশ্রণ বলে বর্ণনা করা হয়; সমস্যাটি P-তে আছে কি না, তা এখনো খোলা প্রশ্ন।

পরীক্ষা ও ইন্টারভিউতে: বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় এই ধরনের প্রশ্ন প্রায়ই আসে:

  • ৮টি vertex আর ১২টি edge-এর গ্রাফের incidence matrix-এর মাপ আর প্রতিটি কলামের যোগফল? 8 × 12; প্রতিটি কলামে 2.
  • trace(A3) = 24 হলে triangle কয়টি? 24/6 = 4.
  • দুটি গ্রাফ isomorphic নয়, কীভাবে দেখাবেন? একটি invariant (degree sequence, triangle, connectedness, bipartiteness) যা দুটিতে আলাদা।
  • {1,…,n}-এ Cn-এর কয়টি লেবেলযুক্ত কপি? n!/(2n) = (n − 1)!/2.
  • Adjacency list না matrix? Sparse গ্রাফে list (n + 2m জায়গা), dense গ্রাফ বা ধ্রুব সময়ে edge-পরীক্ষায় matrix (n2).

১০ · AI-এর যুগে — isomorphism-এর দাবি যাচাই

Graph-এর প্রশ্নে AI সহকারী সংজ্ঞা সাধারণত ঠিক লেখে, কিন্তু নির্দিষ্ট দুটি গ্রাফ নিয়ে আত্মবিশ্বাসী ভুল উত্তর দিতে পারে। কয়েকটি নিয়মিত ভুল আর ধরার উপায়:

AI-এর ভুলকীভাবে ধরবেন
“degree sequence মিলেছে, তাই isomorphic” (converse-এর ভুল)প্রিজম বনাম K3,3 দিয়ে যুক্তিটি পরীক্ষা করুন; একটি স্পষ্ট bijection চান
একটি bijection দেয়, কিন্তু কিছু edge ভুল জায়গায় যায়প্রতিটি edge-এর ছবি নিজে মেলান, বা ছোট Python-এ পরীক্ষা চালান
Triangle বা cycle গুনতে একই জিনিস দুবার বা ছয়বার গোনেtrace(A3)/6-এর সঙ্গে সরাসরি তিন-তিন করে গোনা মেলান
|Aut(G)| ভুল বলে, বা n!/|Aut|-কে লেবেলহীন গ্রাফের সংখ্যা ভাবেছোট n-এ সব permutation চালিয়ে automorphism গুনুন
“GI NP-complete” বা “GI polynomial” বলে দাবি, বানানো উৎসসহদাবিটির উৎস চান; বর্তমান অবস্থা: NP-তে আছে, কোনোটিই প্রমাণিত নয়

AI-এর কাছে দুটি গ্রাফের isomorphism বা অ-isomorphism প্রমাণ চাইলে এমন কাঠামো দিন, যাতে প্রতিটি দাবি আলাদা করে যাচাই করা যায়:

নিচের দুটি গ্রাফ isomorphic কি না নির্ণয় করো: G: [edge list, যেমন 1-2 2-3 3-1 4-5 5-6 6-4 1-4 2-5 3-6] H: [edge list, যেমন a-x a-y a-z b-x b-y b-z c-x c-y c-z] ১. প্রথমে দুটির n, m, degree sequence, triangle-এর সংখ্যা আর connectedness একটি সারণিতে দাও, প্রতিটি সংখ্যা কীভাবে গুনেছ তা দেখাও। ২. isomorphic বললে পুরো bijection f লেখো, আর G-এর প্রতিটি edge-এর ছবি H-এ কোন edge তা তালিকা করো। ৩. isomorphic নয় বললে ঠিক কোন invariant আলাদা তা বলো, আর কেন সেটি invariant তার এক লাইনের প্রমাণ দাও। ৪. "সব invariant মিলেছে, তাই isomorphic" ধরনের যুক্তি ব্যবহার করবে না। ৫. আমার যাচাইয়ের জন্য শুধু itertools দিয়ে একটি ছোট Python কোড দাও, যা সব bijection পরীক্ষা করে। ৬. জটিলতা বা ইতিহাস নিয়ে কিছু বললে উৎস দাও, আর নিশ্চিত না হলে তা স্পষ্ট বলো।

AI-এর উত্তর হাতে পেলে — যাচাইয়ের চেকলিস্ট

Isomorphism-এর প্রশ্নের একটি বড় সুবিধা: “হ্যাঁ” উত্তরের একটি সার্টিফিকেট আছে (bijection), আর “না” উত্তরেরও প্রায়ই একটি ছোট সার্টিফিকেট থাকে: একটি অমিল invariant-এর হিসাব। AI-এর কাছে সবসময় সেই সার্টিফিকেট চান; সার্টিফিকেট যাচাই করা উত্তর খুঁজে পাওয়ার চেয়ে অনেক সহজ।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।

প্র ০১Graph isomorphism কেন জটিলতা-তত্ত্বের এক “রহস্যময়” সমস্যা? Babai-এর কাজ কী বদলেছে, আর বাস্তবের সফটওয়্যার কীভাবে এটি সামলায়?

NP-এর বেশিরভাগ পরিচিত সমস্যা দুই দলের একটিতে পড়ে: হয় তাদের polynomial algorithm জানা (যেমন shortest path), নয়তো তারা NP-complete (যেমন Hamilton cycle, 3-coloring সমস্যা)। Graph isomorphism দুই দলের কোনোটিতেই প্রমাণিতভাবে নেই, আর Richard Karp ১৯৭২ সালের বিখ্যাত প্রবন্ধে যেসব সমস্যার অবস্থান খোলা রেখেছিলেন, এটি তার একটি বলে উল্লেখ করা হয়। আরও আছে: ১৯৮০-এর দশকের একটি ফল (Boppana, Håstad আর Zachos-এর সঙ্গে যুক্ত) অনুযায়ী GI যদি NP-complete হয়, তবে polynomial hierarchy নামের একটি জটিলতা-স্তরক্রম দ্বিতীয় স্তরে ভেঙে পড়ে, যা বেশিরভাগ গবেষক অসম্ভাব্য মনে করেন। তাই অনেকের ধারণা, GI NP-complete নয়।

László Babai ২০১৫ সালের শেষে ঘোষণা করেন যে GI quasi-polynomial সময়ে সমাধান করা যায়, অর্থাৎ exp((log n)c) সময়ে। এর আগে সাধারণ গ্রাফে সবচেয়ে ভালো জানা সীমা ছিল exp(√(n log n))-এর কাছাকাছি, যা ১৯৮০-এর দশকে Babai আর Eugene Luks-এর কাজের সঙ্গে যুক্ত বলে জানা যায়। ২০১৭ সালের শুরুতে Harald Helfgott বিশ্লেষণে একটি ত্রুটি দেখান, আর Babai কয়েক দিনের মধ্যে একটি সংশোধন ঘোষণা করেন বলে প্রকাশিত হয়। তবু “GI কি P-তে?” প্রশ্নটি খোলা রয়ে গেছে।

বাস্তবে কিন্তু GI খুব কমই সমস্যা করে। Brendan McKay-এর nauty (১৯৮০-এর দশক থেকে) আর পরে Traces, bliss, saucy-এর মতো প্রোগ্রাম একটি গ্রাফের canonical form বানায়: §৮-এর ধারণা, কিন্তু n! টি permutation না দেখে colour refinement দিয়ে vertex-গুলোকে আগে ভাগ করে, আর automorphism খুঁজে পেলে সেগুলো ব্যবহার করে অনুসন্ধান-বৃক্ষের বিশাল অংশ বাদ দেয়। হাজার হাজার vertex-এর বেশিরভাগ গ্রাফ এরা মুহূর্তে সামলায়; কঠিন উদাহরণ সাধারণত বিশেষভাবে বানানো, খুব প্রতিসম গ্রাফ।

মূল উপলব্ধি: GI NP-তে আছে, NP-complete বলে প্রমাণিত নয় (আর সম্ভবত নয়), আর Babai-এর quasi-polynomial algorithm এর তাত্ত্বিক সীমা অনেক নামিয়েছে; বাস্তবে canonical form-ভিত্তিক সফটওয়্যার প্রায় সব ক্ষেত্রে দ্রুত উত্তর দেয়।

প্র ০২বাস্তবের বড় গ্রাফ (রাস্তা, সামাজিক নেটওয়ার্ক, ওয়েব) কোন representation-এ রাখা হয়? তবু adjacency matrix-এর গুরুত্ব কেন কমেনি?

বাস্তবের প্রায় সব বড় গ্রাফ sparse. একটি রাস্তার মোড়ে সাধারণত তিন-চারটি রাস্তা আসে, একজন মানুষ সীমিত সংখ্যক মানুষকে চেনেন, একটি ওয়েব পেজে সীমিত লিংক থাকে। তাই n বাড়লে m মোটামুটি n-এর সমানুপাতে বাড়ে, n2-এর নয়। লাখ লাখ vertex-এর গ্রাফে n2 ঘরের matrix রাখা অসম্ভব, অথচ n + 2m এন্ট্রির adjacency list সহজেই ধরে যায়। বড় আর স্থির গ্রাফের জন্য এর একটি সংকুচিত রূপ, compressed sparse row (CSR), বেশি জনপ্রিয়: সব প্রতিবেশী তালিকা পরপর একটি বড় array-তে, আর প্রতিটি vertex-এর তালিকা কোথায় শুরু, তা আরেকটি array-তে। এতে memory-তে ডেটা কাছাকাছি থাকে আর cache ভালো কাজ করে। DSA কোর্সের পর্ব ৩৯-এ এর কোড আছে।

তবু adjacency matrix গুরুত্বপূর্ণ, কারণ এটি গ্রাফকে রৈখিক বীজগণিতের জগতে নিয়ে যায়। Ak walk গোনে (পর্ব ১৯), trace(A3) triangle গোনে, আর A-এর eigenvalue থেকে গ্রাফের অনেক গঠন বোঝা যায়: এটিই spectral graph theory. Google-এর প্রথম দিকের PageRank ধারণা (Brin আর Page, ১৯৯৮) ওয়েবের লিংক-matrix-এর একটি eigenvector হিসেবে বর্ণনা করা হয়; সেখানে matrix কখনো পুরোটা লেখা হয় না, sparse রূপে রেখে বারবার গুণ করা হয়। অর্থাৎ বাস্তবে “matrix-এর গণিত, list-এর সংরক্ষণ” একসঙ্গে চলে। ২০১০-এর দশকে GraphBLAS নামের একটি মানদণ্ড এই ধারণাকেই সাধারণ করেছে বলে জানা যায়: BFS-এর মতো গ্রাফ algorithm-কে sparse matrix-vector গুণ হিসেবে লেখা।

Incidence matrix-ও তত্ত্বে বেঁচে আছে। বৈদ্যুতিক সার্কিটে oriented incidence matrix দিয়ে Kirchhoff-এর current সূত্র এক লাইনে লেখা যায়, আর BBT-এর directed রূপ থেকে Laplacian matrix আসে, যা spanning tree গোনে (পর্ব ৬৭-এ Kirchhoff-এর গণনা)।

মূল উপলব্ধি: সংরক্ষণের জন্য sparse গ্রাফে list বা CSR প্রায় সবসময় ভালো, কিন্তু প্রমাণ আর বিশ্লেষণের জন্য matrix অপরিহার্য; ভালো প্রকৌশলে দুটি দৃষ্টিভঙ্গি একসঙ্গে ব্যবহার হয়।

প্র ০৩রসায়নে isomorphism আর canonical form কীভাবে কাজে লাগে? “graph” শব্দটিই বা কোথা থেকে এলো?

একটি অণুকে গ্রাফ হিসেবে দেখা যায়: পরমাণু vertex, রাসায়নিক বন্ধন edge. একই আণবিক সংকেতের (যেমন C4H10) কিন্তু ভিন্ন গঠনের অণুকে বলে isomer; বিউটেন আর আইসোবিউটেন এর সবচেয়ে সহজ উদাহরণ। গ্রাফের ভাষায় এরা একই vertex-সংখ্যার কিন্তু অ-isomorphic দুটি গ্রাফ; কার্বনের কাঠামোটি একটি path বনাম একটি তারা, আর degree sequence-ই তাদের আলাদা করে। Arthur Cayley ১৮৭০-এর দশকে alkane-এর isomer গুনতে tree গোনার পদ্ধতি ব্যবহার করেছিলেন বলে জানা যায়; গ্রাফ গোনা আর রসায়নের এই যোগাযোগ পরে Pólya-র ১৯৩৭ সালের কাজে আরও গভীর হয় (পর্ব ৫১)।

“graph” শব্দটি গণিতে আনার কৃতিত্ব সাধারণত James Joseph Sylvester-কে দেওয়া হয়, যিনি ১৮৭৮ সালের একটি লেখায় রসায়নবিদদের অণু আঁকার পদ্ধতি (“chemicograph”) থেকে শব্দটি নেন বলে উল্লেখ করা হয়। অর্থাৎ গ্রাফ তত্ত্বের নামের মধ্যেই রসায়ন লুকিয়ে আছে।

আধুনিক রাসায়নিক ডেটাবেসে কোটি কোটি অণু থাকে, আর নতুন একটি অণু আগে থেকে আছে কি না, তা জানতে প্রতিবার isomorphism পরীক্ষা অসম্ভব। তাই §৮-এর ধারণাই কাজে লাগে: প্রতিটি অণুর একটি canonical লেখা। “canonical SMILES” নামের একটি রীতি অণুকে একটি নির্দিষ্ট string-এ লেখে, আর IUPAC-এর InChI (২০০০-এর দশকের মাঝামাঝি থেকে) একই উদ্দেশ্যে একটি মানদণ্ড; দুটি অণু একই হলে তাদের canonical string এক, তাই ডেটাবেসে খোঁজা মানে string মেলানো। এখানে পরমাণুর ধরন (C, H, O) vertex-এর “রঙ” আর বন্ধনের ধরন (একক, দ্বি) edge-এর রঙ, তাই isomorphism-কে রঙ ঠিক রাখতে হয়, যা সমস্যাটিকে সহজও করে, কারণ রঙ প্রথম থেকেই vertex-গুলোকে ভাগ করে দেয়।

একটি সীমাও আছে: গ্রাফ শুধু কে কার সঙ্গে যুক্ত তা বলে, ত্রিমাত্রিক বিন্যাস নয়। একই গ্রাফের দুটি অণু আয়নার প্রতিবিম্বের মতো হতে পারে (stereoisomer), আর ওষুধের ক্ষেত্রে সেই পার্থক্য গুরুত্বপূর্ণ হতে পারে। তাই রসায়নের canonical form-এ গ্রাফের বাইরে অতিরিক্ত তথ্যও লেখা হয়।

মূল উপলব্ধি: রসায়নে isomer মানে অ-isomorphic গ্রাফ, আর বিশাল ডেটাবেসে খোঁজার কৌশল হলো canonical form; গ্রাফ তত্ত্বের নাম আর গণনার ইতিহাস দুটিই রসায়নের সঙ্গে জড়িত।

প্র ০৪Petersen graph কোথা থেকে এলো, আর একে কেন গ্রাফ তত্ত্বের “পাল্টা-উদাহরণের কারখানা” বলা হয়?

গ্রাফটির নাম ডেনমার্কের গণিতবিদ Julius Petersen-এর নামে, যিনি ১৮৯৮ সালের একটি প্রবন্ধে এটি প্রকাশ করেন বলে জানা যায়। প্রসঙ্গ ছিল চার রঙের সমস্যার সঙ্গে যুক্ত একটি প্রশ্ন: Peter Guthrie Tait দেখিয়েছিলেন যে চার রঙের উপপাদ্য একটি কথার সমতুল্য, “bridge নেই এমন প্রতিটি 3-regular planar গ্রাফের edge তিন রঙে রাঙানো যায়”। Petersen দেখান যে “planar” শর্তটি বাদ দেওয়া যায় না: তাঁর গ্রাফটি 3-regular আর bridge-হীন, কিন্তু তার edge তিন রঙে রাঙানো যায় না। এই পর্বের scratch-এ সব সম্ভাবনা backtracking দিয়ে পরীক্ষা করে একই ফল পাওয়া গেছে। গ্রাফটি এর আগে ১৮৮৬ সালে Alfred Kempe-এর একটি লেখাতেও এসেছিল বলে উল্লেখ করা হয়।

এরপর থেকে নতুন অনুমান পরীক্ষার প্রথম পাথর হয়ে ওঠে এই গ্রাফ। এতে Hamilton cycle নেই, অথচ একটি vertex সরালেই বাকি গ্রাফে Hamilton cycle থাকে; এমন গ্রাফকে hypohamiltonian বলে। এটি planar নয়, অথচ এতে K5 বা K3,3 সরাসরি subgraph হিসেবে নেই; Kuratowski-এর উপপাদ্যে “subdivision” বা minor-এর ধারণা কেন লাগে, তা এটি দেখায় (পর্ব ৬২)। Girth 5 আর degree 3 নিয়ে এটিই সবচেয়ে কম vertex-এর গ্রাফ (Moore bound-এর সঙ্গে সম্পর্কিত একটি ধ্রুপদি ফল)। Donald Knuth-এর একটি প্রায়ই উদ্ধৃত মন্তব্য অনুযায়ী, Petersen graph গ্রাফ তত্ত্বের অনেক আশাবাদী অনুমানের বিপরীতে একটি পাল্টা-উদাহরণ হয়ে দাঁড়ায়।

যেসব 3-regular, bridge-হীন গ্রাফের edge তিন রঙে রাঙানো যায় না, Martin Gardner ১৯৭৬ সালে তাদের নাম দেন “snark” বলে জানা যায় (Lewis Carroll-এর কবিতার একটি অধরা প্রাণী থেকে)। Petersen graph সবচেয়ে ছোট snark. ১৯৯০-এর দশকের শেষে Neil Robertson-সহ কয়েকজন গবেষক Tutte-এর একটি অনুমানের বিশেষ রূপ প্রমাণ করেন বলে জানা যায়: প্রতিটি snark-এর একটি Petersen minor আছে।

এত ধর্মের পেছনে আছে বিশাল symmetry: |Aut| = 120, আর যেকোনো vertex-কে যেকোনো vertex-এ, এমনকি যেকোনো দিকযুক্ত edge-কে যেকোনো দিকযুক্ত edge-এ পাঠানো যায়। তাই গ্রাফটির কোনো “বিশেষ কোণা” নেই যেখান থেকে একটি প্রমাণ শুরু হতে পারে।

মূল উপলব্ধি: Petersen graph ছোট, অত্যন্ত প্রতিসম, আর একসঙ্গে অনেক “সাধারণত সত্য” কথার ব্যতিক্রম; একটি নতুন অনুমান মনে এলে প্রথমে এটিতে পরীক্ষা করুন।

প্র ০৫Graph neural network (GNN) কোন দুটি গ্রাফ আলাদা করতে পারে না, আর তার সঙ্গে Weisfeiler–Leman-এর ১৯৬৮ সালের ধারণার সম্পর্ক কী?

Boris Weisfeiler আর Andrei Leman ১৯৬৮ সালে একটি প্রবন্ধে গ্রাফকে একটি স্বাভাবিক রূপে আনার একটি পদ্ধতি প্রকাশ করেন বলে জানা যায়, যার সরলতম রূপ আজ colour refinement বা 1-WL নামে পরিচিত: প্রতিটি vertex নিজের রঙ আর প্রতিবেশীদের রঙের বহুসেট দেখে নতুন রঙ নেয়, আর রঙ আর না বদলানো পর্যন্ত এটি চলে। দুটি গ্রাফে শেষ রঙের হিসাব আলাদা হলে তারা নিশ্চিতভাবে অ-isomorphic; এটি একটি শক্তিশালী invariant, যা “প্রায় সব” গ্রাফকে আলাদা করে বলে জানা যায়।

কিন্তু regular গ্রাফে এটি অন্ধ। প্রিজম আর K3,3 দুটিই 3-regular: শুরুতে সব vertex এক রঙ, আর প্রত্যেকের তিনজন প্রতিবেশী সেই একই রঙের, তাই পরের ধাপেও সবাই এক রঙ। Refinement থেমে যায়, আর দুটি গ্রাফ একই দেখায়, যদিও একটিতে triangle আছে, অন্যটিতে নেই। একইভাবে একই মাপের যেকোনো দুটি k-regular গ্রাফ এর চোখে এক।

আধুনিক graph neural network-এর একটি বড় শ্রেণি (message passing) ঠিক এই কাজই করে, শুধু রঙের বদলে সংখ্যার vector দিয়ে: প্রতিটি স্তরে প্রতিটি vertex প্রতিবেশীদের vector জড়ো করে নিজেকে হালনাগাদ করে। ২০১৯ সালে দুটি গবেষক দল (Keyulu Xu ও সহকর্মীরা, এবং Christopher Morris ও সহকর্মীরা) প্রায় একই সময়ে দেখান যে এমন GNN দুটি গ্রাফকে আলাদা করার ক্ষমতায় 1-WL-এর চেয়ে বেশি শক্তিশালী হতে পারে না বলে জানা যায়। অর্থাৎ শুধু গঠন দেখে কোনো সাধারণ message-passing GNN প্রিজম আর K3,3-এর জন্য আলাদা উত্তর দিতে পারে না, যদি না vertex-গুলোতে আলাদা বৈশিষ্ট্য দেওয়া থাকে।

এই সীমা পার হতে গবেষকেরা উচ্চতর k-WL-এর অনুকরণ, vertex-এ এলোমেলো বা অবস্থানগত বৈশিষ্ট্য যোগ, বা triangle-এর মতো ছোট গঠন আগে গুনে দেওয়ার মতো কৌশল ব্যবহার করেন। ব্যাপারটি এই পর্বের মূল শিক্ষার প্রতিধ্বনি: একটি invariant যত শক্তিশালীই হোক, complete না হলে এমন জোড়া থাকবে যাদের সে আলাদা করতে পারে না।

মূল উপলব্ধি: Message-passing GNN-এর আলাদা করার ক্ষমতা colour refinement দিয়ে সীমাবদ্ধ, আর regular গ্রাফে সেই refinement কিছুই দেখে না; প্রিজম বনাম K3,3 তাই যন্ত্র-শিক্ষাতেও একটি আদর্শ পরীক্ষা।

অনুশীলন

আগে খাতায় করুন, তারপর উত্তর খুলে মেলান।

  1. প্রমাণ: G-এর complement Ḡ-এর vertex একই, আর {u, v} (u ≠ v) Ḡ-এর edge ঠিক তখন, যখন সেটি G-এর edge নয়। প্রমাণ করুন: G ≅ H হলে Ḡ ≅ H̄. তারপর দেখান C5 তার নিজের complement-এর সঙ্গে isomorphic হয়।
    1. f : V → W একটি isomorphism নিন। u ≠ v-এর জন্য {u, v} ∈ E(Ḡ) ⇔ {u, v} ∉ E(G). — complement-এর সংজ্ঞা
    2. {u, v} ∉ E(G) ⇔ {f(u), f(v)} ∉ E(H), কারণ f-এর শর্তটি “⇔”, তাই দুই দিকের negation-ও সমতুল্য। — সংজ্ঞা ৪.১
    3. {f(u), f(v)} ∉ E(H) ⇔ {f(u), f(v)} ∈ E(H̄), আর f injective বলে f(u) ≠ f(v). তাই একই f, Ḡ থেকে H̄-তে isomorphism. ∎ — complement-এর সংজ্ঞা

    C5-এর (vertex 1–5, edge 12, 23, 34, 45, 51) complement-এর edge বাকি পাঁচটি জোড়া: 13, 14, 24, 25, 35. এরা একটি তারা: 1–3–5–2–4–1. ফাংশন g: 1→1, 2→3, 3→5, 4→2, 5→4 নিলে C5-এর edge 12 → 13, 23 → 35, 34 → 52, 45 → 24, 51 → 41, সবগুলো complement-এর edge (scratch-এ মেলানো)। তাই C5 self-complementary; ছবি ৪.১-এর তারাটি আসলে C5-এর complement.

  2. হিসাব: (ক) ৭টি vertex আর ১০টি edge-এর একটি loop-হীন গ্রাফের incidence matrix-এর মাপ কত, আর তার সব ঘরের যোগফল কত? (খ) একটি simple graph-এর adjacency matrix-এর জন্য trace(A2) = 18 আর trace(A3) = 12. edge আর triangle কয়টি? (গ) {1, 2, 3, 4, 5, 6}-এর ওপর কয়টি আলাদা লেবেলযুক্ত গ্রাফ প্রিজমের isomorphic, আর কয়টি K3,3-এর?

    (ক) সারি = vertex, কলাম = edge: 7 × 10. প্রতিটি কলামে 2, তাই যোগফল 2 × 10 = 20.

    (খ) trace(A2) = 2m, তাই m = 9; trace(A3) = 6t, তাই t = 2. (প্রিজম ঠিক এমন একটি গ্রাফ।)

    (গ) উপপাদ্য ৭.৩: প্রিজম 6!/|Aut| = 720/12 = 60; K3,3 720/72 = 10. K3,3-এর ক্ষেত্রে সরাসরি গোনা যায়: ছয়টি নামকে দুটি তিনজনের দলে ভাগ করার উপায় C(6, 3)/2 = 10, আর দল ঠিক হলে গ্রাফ ঠিক। (দুটি |Aut| scratch-এ সব 720টি permutation পরীক্ষা করে মেলানো।)

  3. আউটপুট অনুমান: কোড না চালিয়ে বলুন কী ছাপা হবে, আর প্রতিটি সংখ্যা গ্রাফের কোন তথ্য। তারপর যেকোনো Python-এ চালিয়ে মেলান।
    A = [[0,1,1,0],[1,0,1,1],[1,1,0,1],[0,1,1,0]]
    A2 = [[sum(A[i][k]*A[k][j] for k in range(4)) for j in range(4)]
          for i in range(4)]
    print([A2[i][i] for i in range(4)], A2[0][3])
    print(sum(A2[i][j]*A[j][i] for i in range(4) for j in range(4)) // 6)
    [2, 3, 3, 2] 2
    2

    গ্রাফটি K4 থেকে edge {0, 3} বাদ দেওয়া, যাকে অনেকে “diamond” গ্রাফ বলেন। প্রথম তালিকা A2-এর কর্ণ, অর্থাৎ degree: 2, 3, 3, 2. A2[0][3] = vertex 0 আর 3-এর সাধারণ প্রতিবেশী (1 আর 2), তাই 2. শেষ লাইনের যোগফল ∑i,j(A2)ijaji = trace(A3) = 12, আর 12 // 6 = 2: triangle {0, 1, 2} আর {1, 2, 3}. আউটপুট CPython 3.14-এ চালিয়ে মেলানো।

  4. প্রমাণের ভুল ধরুন: একজন লিখলেন: “G-এর vertex 1, 2, 3 আর edge {1,2}, {2,3}; H-এর vertex a, b, c আর edge {a,b}, {b,c}, {a,c}. f(1) = a, f(2) = b, f(3) = c একটি bijection, আর G-এর প্রতিটি edge-এর ছবি H-এর একটি edge: {a,b} আর {b,c}. তাই G ≅ H সত্য।” ভুল কোথায়? কোন অতিরিক্ত শর্ত থাকলে “edge থেকে edge” যুক্তিটি যথেষ্ট হতো?
    • ভুল ধাপ: সংজ্ঞা ৪.১ “⇔” চায়: non-edge-কেও non-edge-এ যেতে হবে। G-এ {1, 3} edge নয়, কিন্তু তার ছবি {a, c} H-এর edge. লেখক শুধু এক দিক (⇒) পরীক্ষা করেছেন।
    • সরাসরি পাল্টা যুক্তি: G-তে edge ২টি, H-এ ৩টি; উপপাদ্য ৫.২(ক)-এর invariant আলাদা, তাই কোনো bijection-ই isomorphism হতে পারে না। G হলো path P3, H হলো triangle K3.
    • সংশোধন: f bijection, প্রতিটি edge-কে edge-এ পাঠায়, আর |E(G)| = |E(H)| হলে যুক্তিটি ঠিক: তখন edge-এর ওপর f-এর ফাংশন injective আর দুই সেট সমান মাপের, তাই onto (§৪-এর যুক্তি)। এখানে 2 ≠ 3, তাই যুক্তি ভেঙে পড়ে।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রম“V-এর ওপর G-এর isomorphic গ্রাফ ঠিক n!/|Aut(G)|টি” প্রমাণের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. V-এর প্রতিটি permutation σ থেকে একটি কপি σ(G) পাওয়া যায়
  2. প্রতিটি কপি কোনো না কোনো permutation থেকে আসে, কারণ তার isomorphism নিজেই একটি permutation
  3. σ(G) = τ(G) ঠিক তখন, যখন τ−1σ একটি automorphism
  4. তাই প্রতিটি কপি ঠিক |Aut(G)|টি permutation থেকে আসে
  5. সিদ্ধান্ত: n! টি permutation সমান দলে ভাগ হয়, কপি n!/|Aut(G)|টি

একটি simple graph-এর adjacency matrix A. A2-এর কর্ণের ঘর (A2)ii কী বোঝায়?

  • vi যত triangle-এ আছে তার সংখ্যা
  • deg(vi)
  • সবসময় 0
  • গ্রাফের মোট edge-সংখ্যা

একটি simple graph-এর adjacency matrix A-এর জন্য trace(A3) = 30. গ্রাফে কয়টি triangle?

  • 30
  • 10
  • 5
  • 15

নিচের কোনটি graph invariant নয়, অর্থাৎ isomorphic দুটি গ্রাফে আলাদা হতে পারে?

  • Degree sequence
  • Triangle-এর সংখ্যা
  • গ্রাফটি connected কি না
  • “1” নামের vertex-এর degree

{1, 2, 3, 4, 5}-এর ওপর কয়টি আলাদা লেবেলযুক্ত গ্রাফ পাঁচ-কোণ C5-এর isomorphic?

  • 12
  • 120
  • 24
  • 1

প্রিজম (দুটি triangle আর তিনটি স্পোক) আর K3,3 দুটিতেই ৬টি vertex, ৯টি edge আর সব degree 3. নিচের কোন তথ্য তাদের অ-isomorphic প্রমাণ করে?

  • Edge-সংখ্যা
  • Connectedness
  • Triangle-এর সংখ্যা
  • Degree sequence

সাধারণ গ্রাফের জন্য graph isomorphism সমস্যার জটিলতা সম্পর্কে কোন কথাটি বর্তমানে জানা তথ্যের সঙ্গে মেলে?

  • এটি NP-complete বলে প্রমাণিত
  • এটি NP-তে আছে, NP-complete বলে প্রমাণিত নয়, আর quasi-polynomial সময়ের algorithm জানা
  • এটির polynomial সময়ের algorithm প্রমাণিত
  • কোনো algorithm দিয়েই এটি সমাধান করা যায় না

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. তিন representation: adjacency list (n + 2m জায়গা, sparse গ্রাফে সেরা), adjacency matrix (n2, symmetric, ধ্রুব সময়ে edge-পরীক্ষা), incidence matrix (n × m, প্রতিটি কলামে ঠিক দুটি 1).
  2. Matrix-এর তথ্য: সারির যোগফল = degree, (A2)ii = deg(vi), trace(A2) = 2m, trace(A3) = 6 × triangle, BBT = D + A.
  3. Isomorphism: edge আর non-edge দুটোই রক্ষা করে এমন bijection; দেখাতে হলে bijection দিন, না দেখাতে হলে একটি অমিল invariant.
  4. Invariant-এর সীমা: n, m, degree sequence, connectedness মিললেও গ্রাফ আলাদা হতে পারে (প্রিজম বনাম K3,3); “invariant সমান ⇒ isomorphic” converse-এর ভুল।
  5. Symmetry আর গণনা: |Aut(Cn)| = 2n, Petersen graph-এর |Aut| = 120; লেবেলযুক্ত কপি n!/|Aut(G)|, আর canonical form প্রতিটি শ্রেণির একটি নির্দিষ্ট প্রতিনিধি দেয়।

পরের পর্বে: পর্ব ৫৯ “Connectivity — path, component, cut vertex আর Menger-এর ধারণা”: এই পর্বের connectedness invariant-টির ভেতরে ঢোকা হবে, walk থেকে path, component, আর একটি নেটওয়ার্ক ভাঙতে কয়টি হাব বা রুট সরাতে হয় তার গণিত।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান