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

Equivalence relation আর partition

Equivalence Relations and Partitions — Equivalence Classes, the Fundamental Theorem, Bell Numbers, Quotient Sets, Kernels, Refinement and Union-Find

Taught in Bangla, this lesson defines equivalence relations with counterexamples. It proves the fundamental theorem that equivalence relations and partitions are the same thing, counts equivalence relations with Bell and Stirling numbers, and explains quotient sets, well-defined operations, kernels of functions and the factorisation theorem. It covers refinement, intersection, union, equivalence closure and union-find, with in-page Python counting, merging accounts and refuting a bogus reflexivity proof.

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

  • Equivalence relation-এর নির্ভুল সংজ্ঞা, উদাহরণ আর প্রতিটি ধর্ম ভাঙে এমন পাল্টা-উদাহরণ
  • Equivalence relation আর partition-এর মৌলিক উপপাদ্য, দুই দিকের সম্পূর্ণ প্রমাণসহ
  • Equivalence relation গোনা (Bell আর Stirling), আর Python-এ সব তালিকা করে মেলানো
  • Quotient set, well-defined অপারেশন, ফাংশনের kernel আর factorisation উপপাদ্য
  • Refinement, intersection, union, equivalence closure, আর union-find কেন সঠিক উত্তর দেয়

১ · “একই রকম” বলার গণিত — equivalence relation-এর সংজ্ঞা

আমরা প্রতিদিন জিনিসকে দলে ভাগ করি: একই ক্লাসের ছাত্র, একই রুটের রিকশা, একই মাসে জন্ম। প্রতিটি ক্ষেত্রে দুটি বস্তু “কোনো একটি দিক থেকে একই”, যদিও তারা হুবহু এক নয়। এই পর্বের প্রশ্ন: কোন ধরনের “একই” বললে দলগুলো পরিষ্কারভাবে ভাগ হয়, কেউ দুই দলে পড়ে না, আর কেউ বাদ যায় না?

বাজারঘরের ডেলিভারি বিভাগ গ্রাহকদের জেলা অনুযায়ী সাজায়। “রিনা আর সুমন একই জেলার” কথাটির তিনটি স্বাভাবিক বৈশিষ্ট্য আছে: প্রত্যেকে নিজের সঙ্গে একই জেলার; রিনা সুমনের জেলার হলে সুমনও রিনার জেলার; আর রিনা-সুমন একই জেলার এবং সুমন-জয় একই জেলার হলে রিনা-জয়ও একই জেলার। এই তিনটি বৈশিষ্ট্য থাকায় গ্রাহকেরা পরিষ্কার কয়েকটি দলে ভাগ হয়ে যায়: প্রতিটি জেলা একটি দল। অন্যদিকে “রিনা আর সুমনের বাড়ি ৫ কিলোমিটারের মধ্যে” কথাটিতে তৃতীয় বৈশিষ্ট্যটি নেই, আর সেই কারণে এটি দিয়ে গ্রাহকদের দলে ভাগ করা যায় না।

পর্ব ৫২ “Relation আর তার ধর্ম — reflexive, symmetric, transitive”-এ relation-কে একটি সেট হিসেবে দেখা হয়েছে: সেট A-এর ওপর একটি relation R মানে A × A-এর একটি subset (পর্ব ১৪-এর Cartesian product). (a, b) ∈ R হলে লিখি a R b, আর এই পর্বে বিশেষ relation-এর জন্য চিহ্ন a ~ b (পড়ুন “a, b-এর সমতুল্য”)। এখানে সংজ্ঞাগুলো আবার নির্ভুলভাবে লিখে রাখি।

সংজ্ঞা ১.১ (equivalence relation)

সেট A-এর ওপর একটি relation ~ হলো একটি equivalence relation, যদি এটি একসঙ্গে

  • reflexive: প্রতিটি a ∈ A-এর জন্য a ~ a;
  • symmetric: a ~ b হলে b ~ a;
  • transitive: a ~ b আর b ~ c হলে a ~ c.

লক্ষ করুন, reflexive শর্তটি “প্রতিটি a-এর জন্য”, অর্থাৎ এটি সেট A-এর ওপর নির্ভর করে; বাকি দুটি শর্ত “যদি … তবে” ধরনের। এই সূক্ষ্ম পার্থক্যটি §৯-এর ভুল প্রমাণের মূলে।

উদাহরণ (সবগুলো equivalence):

  • Congruence mod m: ℤ-এ a ≡ b (mod m) মানে m ∣ a − b. তিনটি ধর্মের প্রমাণ পর্ব ২২ “Modular arithmetic”-এ আছে (a − a = 0; a − b = km হলে b − a = (−k)m; দুটি সমীকরণ যোগ)। এটিই সব equivalence-এর আদর্শ নমুনা।
  • একই জেলা: গ্রাহকের সেটে a ~ b মানে দুজনের ডেলিভারি জেলা এক।
  • একই দৈর্ঘ্যের string: সব bit string-এর সেটে s ~ t মানে |s| = |t|.
  • একই hash মান: একটি hash function h-এর জন্য x ~ y মানে h(x) = h(y) (পর্ব ২৬ আর পর্ব ৪২-এর hash table-এর একই bucket).
  • Graph isomorphism: দুটি graph-এর vertex-এর নাম বদলে একটিকে অন্যটি বানানো গেলে তারা isomorphic; এটিও একটি equivalence, বিস্তারিত পর্ব ৫৮ “গ্রাফের representation আর isomorphism”-এ।

পাল্টা-উদাহরণ (প্রতিটিতে একটি ধর্ম ভাঙে):

ℤ-এ relationreflexivesymmetrictransitiveযে জোড়া ভাঙে
a ≤ bহ্যাঁনাহ্যাঁ1 ≤ 2, কিন্তু 2 ≰ 1
|a − b| ≤ 1হ্যাঁহ্যাঁনা0 ~ 1, 1 ~ 2, কিন্তু 0 ≁ 2
a < bনানাহ্যাঁ1 < 1 মিথ্যা
ab > 0নাহ্যাঁহ্যাঁ0 · 0 > 0 মিথ্যা
a ≡ b (mod 3)হ্যাঁহ্যাঁহ্যাঁকেউ না: equivalence

শেষের আগের সারিটি মনে রাখার মতো: ℤ-এ “ab > 0” (একই চিহ্নের, শূন্য বাদে) symmetric আর transitive, কিন্তু reflexive নয়, কারণ 0 নিজের সঙ্গেও সম্পর্কিত নয়। “কাছাকাছি” ধরনের সম্পর্ক (দূরত্ব ১-এর মধ্যে, দামের পার্থক্য ১০ টাকার মধ্যে) প্রায় কখনো transitive নয়; ছোট ছোট ধাপ জমে বড় পার্থক্য হয়।

২ · Equivalence class — প্রতিটি উপাদানের দল

সংজ্ঞা ২.১ (equivalence class)

~ সেট A-এর ওপর একটি equivalence হলে a ∈ A-এর equivalence class

[a] = {x ∈ A : x ~ a}

অর্থাৎ a-এর সমতুল্য সব উপাদানের সেট। class-এর যেকোনো সদস্যকে তার প্রতিনিধি (representative) বলা যায়।

Congruence mod m-এর class হলো পর্ব ২২-এর congruence class [a]m. নিচের stepper-এ {0, 1, …, 11} সেটে mod 4-এর class একে একে বের করা হয়েছে: একটি এখনো-না-দেখা সংখ্যা নিন, তার সমতুল্য সবাইকে তুলে নিন, তারপর পরের না-দেখা সংখ্যায় যান।

1a ~ b ⇔ 4 ∣ a − b2[0] = {0, 4, 8}3[1] = {1, 5, 9}4[2] = {2, 6, 10}5[3] = {3, 7, 11}6[4] = [8] = [0], …
X = {0, 1, …, 11}
class
সদস্য
বাকি
জোড়া
  1. Relation. a ~ b মানে 4 ∣ a − b, অর্থাৎ 4 দিয়ে ভাগ করলে a আর b-এর ভাগশেষ একই। এটি একটি equivalence (পর্ব ২২)।
  2. প্রথম class. সবচেয়ে ছোট না-দেখা সংখ্যা 0. 0 − 4 = −4 আর 0 − 8 = −8, দুটিই 4-এর গুণিতক, তাই [0] = {0, 4, 8}. এই class-এর ভেতরে 3 × 3 = 9টি ক্রমজোড়া (a, b) সম্পর্কিত।
  3. দ্বিতীয় class. পরের না-দেখা সংখ্যা 1: [1] = {1, 5, 9}. মোট জোড়া এখন 18.
  4. তৃতীয় class. [2] = {2, 6, 10}. বাকি থাকল শুধু 3, 7, 11.
  5. চতুর্থ class. [3] = {3, 7, 11}; এখন সবাই কোনো একটি class-এ পড়েছে, আর কেউ দুটিতে পড়েনি।
  6. পুনরাবৃত্তি নয়। [4] বের করলে আবার {0, 4, 8} আসে, অর্থাৎ [4] = [8] = [0]: একই class-এর নাম অনেক। মোট ৪টি আলাদা class, আর relation-এ 4 · 32 = 36টি জোড়া, 12 × 12 = 144টির মধ্যে।

Stepper-এর শেষ ধাপের পর্যবেক্ষণ (“[4] = [0]”) আর “কেউ দুই class-এ পড়ে না” সাধারণভাবে সত্য। পরের lemma-টি এই পর্বের প্রায় সব প্রমাণের ভিত্তি।

Lemma ২.২ (তিনটি সমতুল্য কথা)

~ সেট A-এর ওপর একটি equivalence আর a, b ∈ A হলে নিচের তিনটি কথা সমতুল্য: (ক) a ~ b; (খ) [a] = [b]; (গ) [a] ∩ [b] ≠ ∅.

  1. (ক) ⇒ (খ): ধরুন a ~ b. x ∈ [a] নিলে x ~ a, আর a ~ b, তাই transitive ধর্মে x ~ b, অর্থাৎ x ∈ [b]. তাই [a] ⊆ [b]. — transitive
  2. symmetric ধর্মে b ~ a, তাই একই যুক্তিতে [b] ⊆ [a]; দুই দিকের অন্তর্ভুক্তি থেকে [a] = [b]. — symmetric, পর্ব ১৪-এর double inclusion
  3. (খ) ⇒ (গ): reflexive ধর্মে a ~ a, তাই a ∈ [a] = [b], আর ছেদ খালি নয়। — reflexive
  4. (গ) ⇒ (ক): c ∈ [a] ∩ [b] নিন। তাহলে c ~ a আর c ~ b. symmetric ধর্মে a ~ c, তারপর transitive ধর্মে a ~ b. ∎ — symmetric, transitive

প্রমাণে তিনটি ধর্মের প্রতিটি ঠিক এক জায়গায় লেগেছে। ফলাফলটি এক বাক্যে: দুটি class হয় হুবহু সমান, নয়তো একেবারে আলাদা; আংশিক মিল বলে কিছু নেই।

৩ · মৌলিক উপপাদ্য — equivalence relation আর partition একই জিনিস

সেট A-এর একটি partition (দলভাগ) হলো A-এর খালি-নয় এমন কয়েকটি subset-এর একটি সংগ্রহ, যাদের বলে block, যাতে প্রতিটি উপাদান ঠিক একটি block-এ পড়ে। অর্থাৎ block-গুলো খালি নয়, দুটি-দুটি করে পরস্পর বিচ্ছিন্ন, আর সবগুলোর union পুরো A. এই ধারণাটি পর্ব ৩৯-এ sample space ভাগ করতে আর পর্ব ৫০-এ গোনার জন্য এসেছে।

উপপাদ্য ৩.১ (equivalence আর partition-এর মৌলিক উপপাদ্য)

(ক) ~ সেট A-এর ওপর একটি equivalence হলে তার আলাদা আলাদা class-গুলো A-এর একটি partition.
(খ) উল্টো দিকে, P যদি A-এর একটি partition হয়, তাহলে “a ~P b ⇔ a আর b একই block-এ” একটি equivalence, যার class-গুলো ঠিক P-এর block.
(গ) এই দুটি রূপান্তর একে অন্যের উল্টো, তাই A-এর equivalence relation আর A-এর partition-এর মধ্যে একটি bijection আছে।

(ক)-এর প্রমাণ।

  1. প্রতিটি class খালি নয়: a ∈ [a]. — reflexive
  2. class-গুলোর union পুরো A: যেকোনো a ∈ A নিজের class [a]-তে আছে। — ধাপ ১
  3. দুটি আলাদা class বিচ্ছিন্ন: [a] ≠ [b] হলে lemma ২.২-এর (খ) ⇔ (গ) অনুযায়ী [a] ∩ [b] = ∅. ∎ — lemma ২.২

(খ)-এর প্রমাণ। প্রতিটি a-এর জন্য B(a) দিয়ে বোঝাই a যে একমাত্র block-এ আছে।

  1. Reflexive: a আর a একই block B(a)-তে। — partition-এ প্রতিটি উপাদান কোনো block-এ
  2. Symmetric: a আর b একই block-এ থাকলে b আর a-ও একই block-এ। — “একই block” কথাটি দুই দিকে একই
  3. Transitive: a, b একই block-এ আর b, c একই block-এ। b ঠিক একটি block-এ আছে, তাই দুটি block একই, B(a) = B(b) = B(c), আর a ~P c. — block-গুলো বিচ্ছিন্ন
  4. a-এর class = {x : x আর a একই block-এ} = B(a), তাই class-গুলো ঠিক P-এর block. ∎ — class-এর সংজ্ঞা

(গ)-এর প্রমাণ। ~ থেকে partition বানিয়ে আবার relation বানালে পাই “a আর b একই class-এ”, যা lemma ২.২ অনুযায়ী ঠিক a ~ b. আর P থেকে relation বানিয়ে আবার class নিলে (খ)-এর ধাপ ৪ অনুযায়ী P-ই ফিরে আসে। দুই দিকের composition identity, তাই দুটি রূপান্তর পরস্পরের উল্টো, আর পর্ব ১৬ অনুযায়ী দুটিই bijection. ∎

ছবিতে কথাটি এরকম: এক দিকে দলভাগ, অন্য দিকে zero-one matrix (পর্ব ১৯)। Row আর column একই দলের সদস্যদের পাশাপাশি রেখে সাজালে matrix-এর 1-গুলো কর্ণ বরাবর কয়েকটি বর্গাকার block-এ জমে, আর বাকি সব 0.

একই জিনিসের দুই রূপ: partition আর equivalence relation-এর matrix

বাজারঘরের ৬ জন গ্রাহক, জেলা অনুযায়ী ৩টি দল। নিচের matrix-এ row আর column-এর ক্রম 1, 3, 2, 5, 6, 4; প্রতিটি রঙিন বর্গ একটি class.

A partition of six customers into three districts and the block-diagonal zero-one matrix of the matching equivalence relation ঢাকারাজশাহীখুলনা 13 256 4 a ~ b ⇔ একই জেলা · matrix-এ M[a][b] = 1 1 3 2 5 6 4 1 3 2 5 6 4 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 1 জোড়া = 2² + 3² + 1² = 14

ছবির শেষ লাইনটি একটি দরকারি সূত্র: block-গুলোর আকার s1, s2, …, sk হলে relation-এ ঠিক s12 + s22 + ⋯ + sk2টি ক্রমজোড়া, কারণ একটি block-এর ভেতরে যেকোনো দুজন (নিজেকে নিজের সঙ্গেসহ) সম্পর্কিত। নিচের stepper দুই দিকের রূপান্তর হাতে করে দেখায়।

1P = {{1,3}, {2,5}, {4}}2block {1,3} → জোড়া3block {2,5} → জোড়া4block {4} → জোড়া5উল্টো: matrix-এর সারি 1, 26সারি 3, 4, 5 → partition
A = {1, 2, 3, 4, 5}
এখন
নতুন
মোট
  1. Partition যাচাই। P-এর তিনটি block খালি নয়, কোনো দুটির মধ্যে মিল নেই, আর একসঙ্গে 1 থেকে 5 সবাইকে ঢাকে। তাই P একটি partition, আর উপপাদ্য ৩.১(খ) একটি equivalence দেয়।
  2. প্রথম block. {1, 3}-এর ভেতরে প্রতিটি ক্রমজোড়া: (1,1), (1,3), (3,1), (3,3). 22 = 4টি জোড়া।
  3. দ্বিতীয় block. {2, 5} থেকে আরও 4টি: (2,2), (2,5), (5,2), (5,5). মোট 8.
  4. এক-সদস্যের block. {4} থেকে শুধু (4,4). এটি বাদ দিলে relation reflexive থাকত না। মোট 22 + 22 + 12 = 9টি জোড়া, 25টির মধ্যে।
  5. উল্টো পথ। এবার শুধু matrix দেওয়া আছে ধরুন। সারি a-তে যেসব column-এ 1, সেগুলোই [a]: সারি 1 থেকে [1] = {1, 3}, সারি 2 থেকে [2] = {2, 5}.
  6. Partition ফিরে আসে। সারি 3 হুবহু সারি 1-এর মতো, কারণ [3] = [1] (lemma ২.২); সারি 5 = সারি 2; সারি 4 থেকে {4}. আলাদা সারি ঠিক ৩টি, আর সেগুলোই P-এর block. দুই দিকের রূপান্তর একে অন্যকে বাতিল করে।

৪ · কয়টি equivalence relation — Bell আর Stirling সংখ্যা

মৌলিক উপপাদ্যের সবচেয়ে সরাসরি লাভ গণনায়। n-উপাদানের সেটে relation আছে 2n²টি (n × n matrix-এর প্রতিটি ঘর 0 বা 1). তাদের মধ্যে কয়টি equivalence? প্রশ্নটি কঠিন শোনায়, কিন্তু উপপাদ্য ৩.১(গ)-এর bijection অনুযায়ী উত্তর = n-উপাদানের সেটের partition-এর সংখ্যা, যা পর্ব ৫০ “বিশেষ সংখ্যা — Catalan, Stirling আর partition”-এর Bell সংখ্যা Bn.

উপপাদ্য ৪.১ (equivalence relation গোনা)

n-উপাদানের সেটে equivalence relation-এর সংখ্যা Bn, আর ঠিক k-টি class-যুক্ত equivalence-এর সংখ্যা দ্বিতীয় ধরনের Stirling সংখ্যা S(n, k). B0 = 1 আর

Bn+1 = ∑k=0n C(n, k) · Bk,   Bn = ∑k=1n S(n, k)

প্রমাণ: bijection একটি সেটের আকার অন্য সেটে বহন করে (পর্ব ৩৭-এর bijective গণনা), আর k-টি class মানে k-টি block. Bell-এর recurrence-এর প্রমাণ পর্ব ৫০-এ আছে: n + 1তম উপাদানের block-এ আর কোন কোন উপাদান থাকবে, তা বাছাই করে বাকিদের ভাগ করা। ∎

Bn-এর শুরু: 1, 1, 2, 5, 15, 52, 203, 877, 4140 (n = 0 থেকে 8). তুলনায় relation-এর সংখ্যা n = 3-এ 512, n = 6-এ 236 ≈ ৬,৮৭২ কোটি। নিচের ব্লক দাবিটি দুইভাবে যাচাই করে। n ≤ 3-এ সব relation তালিকা করে তিনটি ধর্ম পরীক্ষা করে। বড় n-এ সব relation দেখা অসম্ভব, তাই কেবল reflexive আর symmetric relation-গুলো দেখে (প্রতিটি অ-কর্ণ জোড়া {a, b} থাকবে কি না, 2C(n,2)টি; n = 6-এ 32768), আর transitive কি না পরীক্ষা করে। প্রথমবার চালালে ব্রাউজারে Python (Pyodide) নামতে কয়েক সেকেন্ড লাগে; পরের ব্লকগুলো দ্রুত চলে।

from itertools import combinations, product
from math import comb
from collections import Counter
def is_equivalence(n, R):              # R = set of pairs (a, b)
    refl = all((a, a) in R for a in range(n))
    sym = all((b, a) in R for a, b in R)
    trans = all((a, d) in R for a, b in R for c, d in R if b == c)
    return refl and sym and trans
# n <= 3: try every one of the 2^(n*n) relations
for n in range(1, 4):
    cells = list(product(range(n), repeat=2))
    hits = sum(is_equivalence(n, {p for p, x in zip(cells, bits) if x})
               for bits in product((0, 1), repeat=n * n))
    print(f"n={n}: {2 ** (n * n):3} relations, {hits} equivalences")
def count_classes(n):                  # only reflexive + symmetric candidates
    edges = list(combinations(range(n), 2))
    by_k = Counter()
    for bits in product((0, 1), repeat=len(edges)):
        nb = [{a} for a in range(n)]   # nb[a] = everything related to a
        for (a, b), x in zip(edges, bits):
            if x:
                nb[a].add(b); nb[b].add(a)
        # transitive <=> related elements have identical neighbour sets
        if all(nb[a] == nb[b] for a in range(n) for b in nb[a]):
            by_k[len({frozenset(s) for s in nb})] += 1
    return by_k
bell = [1]
for m in range(6):                     # B(m+1) = sum C(m, k) B(k)
    bell.append(sum(comb(m, k) * bell[k] for k in range(m + 1)))
for n in range(1, 7):
    by_k = count_classes(n)
    print(f"n={n}: brute {sum(by_k.values()):3}  Bell {bell[n]:3}"
          f"  by #classes {[by_k[k] for k in range(1, n + 1)]}")

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

n=1:   2 relations, 1 equivalences
n=2:  16 relations, 2 equivalences
n=3: 512 relations, 5 equivalences
n=1: brute   1  Bell   1  by #classes [1]
n=2: brute   2  Bell   2  by #classes [1, 1]
n=3: brute   5  Bell   5  by #classes [1, 3, 1]
n=4: brute  15  Bell  15  by #classes [1, 7, 6, 1]
n=5: brute  52  Bell  52  by #classes [1, 15, 25, 10, 1]
n=6: brute 203  Bell 203  by #classes [1, 31, 90, 65, 15, 1]

প্রথম তিন লাইনে সব relation দেখা হয়েছে: ৫১২টির মধ্যে মাত্র ৫টি equivalence, ঠিক B3. পরের ছয় লাইনে brute force আর Bell-এর recurrence প্রতিটি n-এ মিলেছে, আর শেষ তালিকাটি class-এর সংখ্যা অনুযায়ী ভাগ, যা Stirling সংখ্যার সারি: n = 4-এ S(4, 2) = 7, S(4, 3) = 6. Transitive পরীক্ষাটি একটি ছোট উপপাদ্যের ওপর দাঁড়িয়ে: reflexive আর symmetric R transitive হবে যদি এবং কেবল যদি প্রতিটি সম্পর্কিত জোড়া a ~ b-এর “প্রতিবেশী সেট” হুবহু এক হয় (একদিকে lemma ২.২; উল্টো দিকে a ~ b, b ~ c হলে c ∈ nb[b] = nb[a]). আর class-এর সংখ্যা মানে আলাদা প্রতিবেশী সেটের সংখ্যা, ঠিক stepper-এর “আলাদা সারি”।

একটি কাজের কৌশল। “1 আর 2 একই class-এ” এমন equivalence কয়টি, n-উপাদানের সেটে? 1 আর 2-কে একটি উপাদান হিসেবে জুড়ে দিলে বাকি থাকে n − 1টি “উপাদান”, আর যেকোনো partition-এ জোড়টি একসঙ্গে থাকে। তাই উত্তর Bn−1; n = 5-এ B4 = 15 (scratch-এ সব partition তালিকা করে মেলানো)।

৫ · Quotient set আর well-defined অপারেশন

Equivalence-এর সবচেয়ে শক্তিশালী ব্যবহার হলো class-গুলোকে নতুন বস্তু হিসেবে দেখা। প্রতিটি class একটি “উপাদান” হয়ে যায়, আর তার ভেতরের পার্থক্য ভুলে যাওয়া হয়।

সংজ্ঞা ৫.১ (quotient set আর canonical projection)

~ সেট A-এর ওপর একটি equivalence হলে তার সব class-এর সেট A-এর quotient set:

A/~ = {[a] : a ∈ A}

আর π : A → A/~, π(a) = [a] হলো canonical projection, যা প্রতিটি উপাদানকে তার class-এ পাঠায়।

ℤ/≡m হলো পর্ব ২২-এর ℤm = {[0], [1], …, [m − 1]}. π একটি surjection (প্রতিটি class কোনো না কোনো উপাদানের class), কিন্তু সাধারণত one-to-one নয়: π(1) = π(5) = [1] mod 4-এ। পর্ব ১৮-এর ভাষায়, সসীম A-এর জন্য |A/~| ≤ |A|, সমতা শুধু তখন যখন প্রতিটি class এক-সদস্যের।

এখন আসল প্রশ্ন। ℤm-এ যোগ সংজ্ঞায়িত হয় [a] + [b] = [a + b] দিয়ে। কিন্তু ডান পাশের সূত্রটি প্রতিনিধি a আর b ব্যবহার করে, আর একটি class-এর প্রতিনিধি অনেক। ফল যদি প্রতিনিধি বাছাইয়ের ওপর নির্ভর করত, তবে “[a] + [b]” কোনো নির্দিষ্ট class বোঝাত না।

সংজ্ঞা ৫.২ (well-defined)

A/~-এর ওপর প্রতিনিধি দিয়ে লেখা একটি নিয়ম F([a]) = g(a) well-defined, যদি a ~ a′ হলেই g(a) = g(a′) হয়; অর্থাৎ class-এর যেকোনো সদস্য নিলে একই ফল আসে। দুই চলকের নিয়মে শর্তটি দুই চলকেই লাগে।

উদাহরণ ১ (well-defined): mod m-এ যোগ। a ≡ a′ আর b ≡ b′ (mod m) হলে a − a′ = km আর b − b′ = lm, তাই (a + b) − (a′ + b′) = (k + l)m, অর্থাৎ [a + b] = [a′ + b′]. গুণেও একই (পর্ব ২২-এর উপপাদ্য ৩.১)। এভাবেই পর্ব ২২-এর হিসাব “শুধু ভাগশেষ নিয়ে কাজ” করা বৈধ হয়েছিল।

উদাহরণ ২ (well-defined নয়): mod 5-এ ঘাত। [a][b] = [ab] নিয়মটি নিন। 1 ≡ 6 (mod 5), অথচ 21 = 2 আর 26 = 64 ≡ 4 (mod 5). একই class [1] = [6] থেকে দুটি আলাদা ফল, তাই ঘাতে class বসানো যায় না। (ঘাত কোন modulus-এ কমানো যায়, তা পর্ব ২৪-এর Euler-এর উপপাদ্য বলে: সূচক mod φ(m), শর্তসাপেক্ষে।)

উপপাদ্য ৫.৩ (একটি modulus থেকে আরেকটিতে)

m, n ধনাত্মক পূর্ণসংখ্যা হলে নিয়ম F([a]m) = [a]n well-defined যদি এবং কেবল যদি n ∣ m.

  1. ধরুন n ∣ m. a ≡ a′ (mod m) হলে m ∣ a − a′, আর n ∣ m বলে n ∣ a − a′, অর্থাৎ [a]n = [a′]n. — বিভাজ্যতার transitive ধর্ম
  2. উল্টো দিকে ধরুন F well-defined. 0 ≡ m (mod m), তাই [0]n = [m]n, অর্থাৎ n ∣ m − 0 = m. ∎ — একটি নির্দিষ্ট জোড়া পরীক্ষা

যেমন ঘড়ির ঘণ্টা (mod 12) থেকে “সকাল-সন্ধ্যার চার প্রহরের কোনটি” (mod 4) বের করা চলে, কারণ 4 ∣ 12; কিন্তু mod 6 থেকে mod 4 চলে না: [0]6 = [6]6, অথচ [0]4 ≠ [6]4 = [2]4.

৬ · Kernel — প্রতিটি equivalence একটি ফাংশনের “একই মান”

“একই জেলা”, “একই দৈর্ঘ্য”, “একই hash”, “একই ভাগশেষ”: প্রতিটি উদাহরণে একটি ফাংশন লুকিয়ে আছে (জেলা, দৈর্ঘ্য, hash, mod m), আর সম্পর্কটি হলো “ফাংশনের মান সমান”। এটি কাকতালীয় নয়।

সংজ্ঞা ৬.১ আর উপপাদ্য ৬.২ (kernel)

f : A → B যেকোনো ফাংশন হলে x ~f y ⇔ f(x) = f(y) একটি equivalence, যাকে বলে f-এর kernel (ker f). উল্টো দিকে প্রতিটি equivalence ~ কোনো একটি ফাংশনের kernel: ~ = ker π, যেখানে π canonical projection.

  1. f(x) = f(x); f(x) = f(y) হলে f(y) = f(x); f(x) = f(y) আর f(y) = f(z) হলে f(x) = f(z). তাই ~f একটি equivalence. — সমান চিহ্ন “=” নিজেই একটি equivalence
  2. π(x) = π(y) ⇔ [x] = [y] ⇔ x ~ y. ∎ — lemma ২.২

এর ব্যবহারিক অর্থ বড়: আপনি যদি দুটি বস্তুর তুলনা লেখেন key(x) == key(y) আকারে (যেমন email-কে ছোট হাতের অক্ষরে রূপান্তর করে তুলনা), তবে তিনটি ধর্ম আপনাআপনি সত্য, আলাদা করে প্রমাণ করতে হয় না। কিন্তু “দূরত্ব ১-এর কম” ধরনের তুলনা এই আকারে লেখা যায় না, আর সেজন্যই তা transitive নয়।

Kernel-এর ভাষায় প্রতিটি ফাংশনকে তিন টুকরোয় ভাঙা যায়: প্রথমে দলে ভাগ করা, তারপর দল থেকে মানে যাওয়া, শেষে মানটিকে বড় সেটে বসানো।

উপপাদ্য ৬.৩ (ফাংশনের factorisation)

f : A → B, ~ = ker f, আর f(A) হলো f-এর image. তাহলে f̄([a]) = f(a) নিয়মে একটি ফাংশন f̄ : A/~ → f(A) পাওয়া যায়, যা well-defined আর bijection, এবং

f = ι ∘ f̄ ∘ π

যেখানে π : A → A/~ canonical projection (surjection) আর ι : f(A) → B, ι(b) = b অন্তর্ভুক্তি (one-to-one).

  1. Well-defined: a ~ a′ মানে ker f-এর সংজ্ঞায় f(a) = f(a′), তাই f̄([a]) প্রতিনিধির ওপর নির্ভর করে না। — সংজ্ঞা ৫.২
  2. One-to-one: f̄([a]) = f̄([b]) হলে f(a) = f(b), অর্থাৎ a ~ b, আর lemma ২.২ অনুযায়ী [a] = [b]. — kernel-এর সংজ্ঞা
  3. Onto: f(A)-এর প্রতিটি মান কোনো f(a), যা f̄([a]). — image-এর সংজ্ঞা
  4. যেকোনো a-তে (ι ∘ f̄ ∘ π)(a) = ι(f̄([a])) = f(a). ∎ — পর্ব ১৬-এর composition

বাজারঘরের উদাহরণে: f = “গ্রাহকের জেলা”, A/~ = গ্রাহকদের জেলাভিত্তিক দল, আর f̄ প্রতিটি দলকে তার জেলার নাম দেয়, এক দলের এক নাম। ফলাফল হিসেবে একটি গণনা পাওয়া যায়: |A/ker f| = |f(A)|, অর্থাৎ class-এর সংখ্যা = আলাদা মানের সংখ্যা। Hash-এর ভাষায়: যতগুলো আলাদা hash মান আসলে ব্যবহৃত হয়েছে, ঠিক ততগুলো bucket-এ ডেটা আছে।

৭ · Refinement, intersection, union আর সবচেয়ে ছোট equivalence

একই সেটে অনেক equivalence থাকতে পারে, কোনোটি সূক্ষ্ম, কোনোটি মোটা দাগের। “একই থানা” “একই জেলা”-র চেয়ে সূক্ষ্ম: একই থানার দুজন সবসময় একই জেলার।

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

A-এর partition P, partition Q-এর refinement (P, Q-এর চেয়ে সূক্ষ্ম), যদি P-এর প্রতিটি block Q-এর কোনো একটি block-এর ভেতরে থাকে। Relation-এর ভাষায়: ~P ⊆ ~Q.

সবচেয়ে সূক্ষ্ম partition-এ প্রতিটি block এক-সদস্যের (relation শুধু কর্ণ Δ = {(a, a)}), আর সবচেয়ে মোটায় একটিই block (relation পুরো A × A). Congruence-এ: mod 4, mod 2-এর refinement, কারণ 4 ∣ a − b হলে 2 ∣ a − b. সাধারণভাবে mod a, mod b-এর refinement যদি এবং কেবল যদি b ∣ a (উপপাদ্য ৫.৩-এর একই যুক্তি; scratch-এ 1 ≤ a, b ≤ 8 সব জোড়ায় মেলানো)। Partition-গুলো refinement অনুযায়ী একটি “partial order” তৈরি করে, যার আলোচনা পর্ব ৫৬ “Partial order, Hasse diagram, topological sort আর lattice”-এ।

উপপাদ্য ৭.২ (intersection হ্যাঁ, union না)

(ক) A-এর ওপর দুটি (বা যেকোনো সংখ্যক) equivalence-এর intersection আবার একটি equivalence.
(খ) দুটি equivalence-এর union reflexive আর symmetric, কিন্তু transitive না-ও হতে পারে।

  1. (ক) প্রতিটি ~i-তে (a, a) আছে, তাই intersection-এও। (a, b) সবগুলোতে থাকলে প্রতিটি symmetric বলে (b, a)-ও সবগুলোতে। (a, b), (b, c) সবগুলোতে থাকলে প্রতিটি transitive বলে (a, c)-ও সবগুলোতে। — প্রতিটি ধর্ম “সবগুলোতে” কথার সঙ্গে খাপ খায়
  2. (খ) reflexive আর symmetric একইভাবে টিকে যায়। Transitive ভাঙার উদাহরণ: {0, …, 5}-এ R2 = “একই parity”, R3 = “mod 3-এ সমান”। 0 R2 2 আর 2 R3 5, তাই union-এ 0 ~ 2, 2 ~ 5; কিন্তু 0 − 5 = −5, যা ২ বা ৩ কোনোটি দিয়েই বিভাজ্য নয়। ∎ — পাল্টা-উদাহরণ

Intersection-এর class হলো দুই partition-এর block-গুলোর ছেদ, অর্থাৎ দুটির সবচেয়ে মোটা সাধারণ refinement; congruence-এ ≡a ∩ ≡b = ≡lcm(a, b) (পর্ব ২১-এর lcm). Union equivalence না হলে স্বাভাবিক প্রশ্ন: R-কে ধারণ করে এমন সবচেয়ে ছোট equivalence কোনটি?

উপপাদ্য ৭.৩ (equivalence closure)

A-এর ওপর যেকোনো relation R-এর জন্য R-কে ধারণ করে এমন সব equivalence-এর intersection E(R) নিজেই R-কে ধারণকারী সবচেয়ে ছোট equivalence, আর

E(R) = (R ∪ Δ ∪ R−1)*

অর্থাৎ আগে reflexive আর symmetric closure, তারপর transitive closure. x E(R) y মানে x থেকে y-তে R-এর জোড়া ধরে, দিক না মেনে, কোনো পথ আছে।

  1. A × A নিজেই R-কে ধারণকারী একটি equivalence, তাই সংগ্রহটি খালি নয়; উপপাদ্য ৭.২(ক) অনুযায়ী intersection E(R) একটি equivalence, আর সংজ্ঞা অনুযায়ী R-কে ধারণকারী প্রতিটি equivalence-এর ভেতরে। — intersection
  2. S = R ∪ Δ ∪ R−1 reflexive আর symmetric. S* (S-এর জোড়া ধরে পথ) transitive, আর reflexive থাকে কারণ S ⊆ S*. — transitive closure-এর সংজ্ঞা
  3. S* symmetric: x থেকে y-তে S-এর পথ x = v0, v1, …, vk = y থাকলে, S symmetric বলে প্রতিটি ধাপ উল্টানো যায়, তাই y থেকে x-এ উল্টো পথ। সুতরাং S* একটি equivalence যা R-কে ধারণ করে, আর E(R) ⊆ S*. — পথ উল্টানো
  4. উল্টো দিকে, R-কে ধারণকারী যেকোনো equivalence ~ নিজে reflexive আর symmetric, তাই S ⊆ ~; আর transitive বলে S-এর প্রতিটি পথের দুই প্রান্ত ~-এ সম্পর্কিত, অর্থাৎ S* ⊆ ~. তাই S* ⊆ E(R). ∎ — induction, পথের দৈর্ঘ্যে

Closure-এর সাধারণ তত্ত্ব আর Warshall-এর algorithm পর্ব ৫৪ “Relation-এর closure আর Warshall-এর algorithm”-এ আসছে। এখানে লক্ষ করার বিষয় ক্রম: transitive closure শেষে। আগে transitive, পরে symmetric নিলে ফল transitive না-ও হতে পারে (অনুশীলন ৪)। নিচের ব্লক জোড়ার তালিকা থেকে class বের করে, আর উপপাদ্য ৭.২-এর পাল্টা-উদাহরণ যাচাই করে।

def eq_closure(n, pairs):             # smallest equivalence containing pairs
    M = [[i == j for j in range(n)] for i in range(n)]      # reflexive
    for a, b in pairs:
        M[a][b] = M[b][a] = True                            # symmetric
    for k in range(n):                                      # Warshall
        for i in range(n):
            if M[i][k]:
                for j in range(n):
                    M[i][j] = M[i][j] or M[k][j]
    return M

def classes(M):                       # equal rows = one class
    rows = {tuple(j for j, x in enumerate(r) if x) for r in M}
    return sorted(rows)

# same product listed twice: (0,4), (4,7), (2,9), (5,6), (6,2)
M = eq_closure(10, [(0, 4), (4, 7), (2, 9), (5, 6), (6, 2)])
print("product classes:", classes(M))

n = 6                                 # R2 = same parity, R3 = same mod 3
R2 = {(a, b) for a in range(n) for b in range(n) if (a - b) % 2 == 0}
R3 = {(a, b) for a in range(n) for b in range(n) if (a - b) % 3 == 0}
U = R2 | R3
bad = [(a, b, c) for a, b in U for b2, c in U
       if b == b2 and (a, c) not in U]
print("union transitive?", not bad, " first break:", min(bad))
print("intersection = same mod 6?",
      R2 & R3 == {(a, a) for a in range(n)})
print("closure of the union:", classes(eq_closure(n, U)))

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

product classes: [(0, 4, 7), (1,), (2, 5, 6, 9), (3,), (8,)]
union transitive? False  first break: (0, 2, 5)
intersection = same mod 6? True
closure of the union: [(0, 1, 2, 3, 4, 5)]

বাজারঘরের কর্মীরা ১০টি পণ্যের তালিকায় পাঁচ জোড়া “একই পণ্য, দুবার তালিকাভুক্ত” পেয়েছেন। Closure ৫টি class দিল: 0, 4, 7 একই পণ্য, কারণ 0–4 আর 4–7 জোড়া আছে, যদিও 0–7 জোড়াটি কেউ সরাসরি লেখেননি; 2, 5, 6, 9 একইভাবে একটি শৃঙ্খলে যুক্ত; 1, 3, 8 একা। দ্বিতীয় লাইন উপপাদ্য ৭.২(খ)-এর পাল্টা-উদাহরণ: 0 ~ 2 (parity), 2 ~ 5 (mod 3), কিন্তু 0 ≁ 5. তৃতীয় লাইন: {0, …, 5}-এ parity আর mod 3 দুটিতেই সমান মানে mod 6-এ সমান, যা এখানে শুধু কর্ণ। শেষ লাইনে union-এর closure পুরো সেটকে একটি class বানিয়েছে। পূর্ণসংখ্যার ওপর সাধারণভাবে ≡a ∪ ≡b-এর closure = ≡gcd(a, b) (Bézout, পর্ব ২১), আর gcd(2, 3) = 1. Matrix-এর লুপটি Warshall-এর algorithm; তার সঠিকতার প্রমাণ পর্ব ৫৪-এ।

৮ · Union-find — দল জোড়া লাগার সময় class রাখা

Closure-এর matrix পদ্ধতি n2 জায়গা আর প্রায় n3 কাজ নেয়, আর জোড়া একটি একটি করে আসতে থাকলে প্রতিবার আবার হিসাব করতে হয়। বাজারঘরের বাস্তব সমস্যা ঠিক এমন: নতুন অ্যাকাউন্ট খুললেই দেখতে হয়, একই ফোন নম্বর বা email আগে কোনো অ্যাকাউন্টে ছিল কি না; থাকলে দুটি অ্যাকাউন্ট “একই গ্রাহক”। এই সম্পর্কটি জোড়ার equivalence closure, কারণ A1 আর A2-এর email এক, A2 আর A3-এর ফোন এক হলে A1 আর A3-ও একই গ্রাহক, যদিও তাদের কোনো তথ্য সরাসরি মেলে না।

এর জন্য তৈরি ডেটা স্ট্রাকচার union-find (disjoint set union). কোড আর জটিলতার পূর্ণ আলোচনা DSA কোর্সের পর্ব ৩৩ “Disjoint set union (union-find)”-এ; এখানে শুধু গণিত: এটি কী রাখে, আর কেন সঠিক।

  • প্রতিটি উপাদান x-এর একটি parent[x]; parent ধরে উঠতে থাকলে শেষে একটি root পাওয়া যায়, যার parent সে নিজে। find(x) সেই root ফেরত দেয়: এটিই x-এর class-এর প্রতিনিধি।
  • union(a, b): find(a) আর find(b) আলাদা হলে একটি root-কে অন্যটির নিচে বসানো। নিচের stepper-এ ছোট দলের root বড় দলের root-এর নিচে যায়, সমান হলে প্রথম যুক্তির root ওপরে থাকে (union by size).
  • Path compression: find(x) চলার পথে যত node পাওয়া যায়, সবার parent সরাসরি root করে দেওয়া, যাতে পরের বার এক লাফে পৌঁছানো যায়।
1শুরু: parent[x] = x2union(0,1); union(2,3)3union(0,2)4union(4,5); union(6,7)5union(4,6)6union(3,7)7find(5)8find(7)
parent[0] … parent[7] ক্রমে
parent
পথ
class
  1. শুরু। প্রতিটি উপাদান নিজের root: ৮টি এক-সদস্যের class, relation শুধু কর্ণ Δ.
  2. দুটি union. union(0, 1)-এ 1-এর root 1 যায় 0-এর নিচে; union(2, 3)-এ 3 যায় 2-এর নিচে। class এখন {0,1}, {2,3} আর চারটি একা: ৬টি।
  3. দুটি দল জোড়া। union(0, 2): root 0 আর 2, দুই দলের আকার সমান (২), তাই 2 যায় 0-এর নিচে। এখন 3-এর পথ 3 → 2 → 0, গভীরতা ২। class ৫টি: {0,1,2,3} আর 4, 5, 6, 7.
  4. ডান দিকে একই কাজ। union(4, 5) আর union(6, 7): 5 → 4, 7 → 6. class ৩টি: {0,1,2,3}, {4,5}, {6,7}.
  5. আরেকটি জোড়া। union(4, 6): আকার ২ আর ২, তাই 6 যায় 4-এর নিচে। 7-এর পথ এখন 7 → 6 → 4. class ২টি, প্রতিটিতে ৪টি উপাদান।
  6. Compression-সহ union. union(3, 7): find(3) পথ 3 → 2 → 0 দেখে, আর 3-কে সরাসরি 0-এর নিচে বসায়; find(7) পথ 7 → 6 → 4 দেখে, 7-কে 4-এর নিচে বসায়। তারপর root 4 যায় root 0-এর নিচে। সবাই একটি class-এ।
  7. পরের find. find(5): পথ 5 → 4 → 0, তাই 5-কে সরাসরি 0-এর নিচে। parent বদলাল, কিন্তু কোন উপাদান কোন class-এ, তা একটুও বদলায়নি।
  8. আরেকটি find. find(7): পথ 7 → 4 → 0, এখন 7-ও সরাসরি 0-এর নিচে। 6 এখনো 4-এর নিচে, কারণ compression শুধু হাঁটা পথের node বদলায়। Root 0 পুরো class-এর প্রতিনিধি।
উপপাদ্য ৮.১ (union-find-এর সঠিকতা)

শুরুতে প্রতিটি উপাদান নিজের root, তারপর জোড়া (a1, b1), …, (at, bt)-এর জন্য union চালানো হলো (মাঝে মাঝে find-সহ)। প্রতিটি মুহূর্তে find(x) = find(y) যদি এবং কেবল যদি x E y, যেখানে E এ পর্যন্ত আসা জোড়াগুলোর equivalence closure.

  1. Invariant ধরুন: “একই root” relation, যাকে ~root বলি, সবসময় E-এর সমান। ~root একটি ফাংশনের (find-এর) kernel, তাই সবসময় একটি equivalence. — উপপাদ্য ৬.২
  2. Base: শুরুতে root সবার আলাদা, তাই ~root = Δ, আর কোনো জোড়া না আসায় E = Δ. — induction-এর ভিত্তি
  3. find-এর path compression শুধু এমন node-এর parent বদলায় যাদের root আগে থেকেই r, আর নতুন parent সেই r; তাই কারও root বদলায় না, ~root অপরিবর্তিত। — invariant রক্ষা
  4. union(a, b): root ra ≠ rb হলে একটিকে অন্যটির নিচে বসালে ঠিক দুটি class এক হয়, বাকিরা যেমন ছিল। আর E-তে (a, b) যোগ করলে নতুন closure-এও ঠিক [a] আর [b] এক হয়, কারণ নতুন পথ শুধু ওই জোড়া দিয়ে যায়। ra = rb হলে দুই দিকেই কিছু বদলায় না। ∎ — induction-এর ধাপ, উপপাদ্য ৭.৩

এই প্রমাণে union by size বা path compression কোনোটিই সঠিকতার জন্য লাগেনি; ওরা শুধু গতি দেয়। দুটি একসঙ্গে থাকলে m-টি কাজের মোট সময় O(m α(n)), যেখানে α(n) অবিশ্বাস্য ধীরে বাড়া inverse Ackermann ফাংশন। এই সীমা Robert Tarjan ১৯৭৫ সালে প্রমাণ করেন বলে সাধারণত উল্লেখ করা হয়; প্রমাণটি এই কোর্সের বাইরে।

নিচের ব্লক বাজারঘরের ৭টি অ্যাকাউন্টে কাজটি করে, তারপর ২০০টি এলোমেলো জোড়ার তালিকায় union-find আর closure-এর উত্তর মেলায়। এখানে find path compression করে, আর union সরল (b-এর root যায় a-এর root-এর নিচে)।

import random
parent = {}
def find(x):                          # root, with path compression
    root = x
    while parent[root] != root:
        root = parent[root]
    while parent[x] != root:
        parent[x], x = root, parent[x]
    return root
def union(a, b): parent[find(b)] = find(a)
accounts = {"A1": ("017-01", "rina@x"), "A2": ("018-02", "rina@x"),
            "A3": ("018-02", "rk@y"), "A4": ("019-04", "sumon@x"),
            "A5": ("016-05", "joy@y"), "A6": ("019-04", "joy@y"),
            "A7": ("015-07", "nila@x")}
parent.update({a: a for a in accounts})
owner = {}                            # first account seen with a phone/email
for acc, keys in accounts.items():
    for key in keys:
        union(owner.setdefault(key, acc), acc)
print("same customer:", sorted({tuple(a for a in accounts
                                 if find(a) == find(r)) for r in accounts}))
random.seed(55)                       # check against the closure method
for trial in range(200):
    n = random.randint(2, 12)
    pairs = [(random.randrange(n), random.randrange(n)) for _ in range(n)]
    parent.clear(); parent.update({i: i for i in range(n)})
    nb = {i: {i} for i in range(n)}   # closure: grow until nothing changes
    for a, b in pairs:
        union(a, b)
    for _ in range(n):
        for a, b in pairs + [(b, a) for a, b in pairs]:
            nb[a] |= nb[b]
    assert all((find(i) == find(j)) == (j in nb[i])
               for i in range(n) for j in range(n))
print("200 random tests: union-find == closure")

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

same customer: [('A1', 'A2', 'A3'), ('A4', 'A5', 'A6'), ('A7',)]
200 random tests: union-find == closure

ফোন নম্বর আর email স্পষ্টতই কাল্পনিক। A1 আর A3-এর কোনো তথ্য এক নয়, তবু তারা একই গ্রাহক, কারণ A1–A2 email-এ আর A2–A3 ফোনে মেলে: transitivity কাজ করছে। A4 আর A5 একইভাবে A6-এর মাধ্যমে যুক্ত। কোডের কৌশল: owner.setdefault(key, acc) প্রথমবার একটি ফোন বা email দেখলে বর্তমান অ্যাকাউন্টকে তার “মালিক” রাখে, পরে একই key এলে আগের মালিক ফেরত দেয়, আর union দুজনকে জোড়ে (প্রথমবার union(acc, acc) কিছুই বদলায় না)। দ্বিতীয় অংশে closure পদ্ধতি প্রতিটি উপাদানের “সম্পর্কিত সেট” n বার পর্যন্ত ছড়ায় (একটি class-এর দুই সদস্যের মধ্যে পথ n − 1 ধাপের বেশি লাগে না), আর ২০০টি এলোমেলো উদাহরণে প্রতিটি জোড়া (i, j)-এ দুই পদ্ধতির উত্তর এক। assert ব্যর্থ হলে ব্লকটি error দিত।

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

Orbit: symmetry থেকে আসা equivalence

পর্ব ৫১ “Symmetry দিয়ে গণনা — Burnside-এর lemma আর Pólya”-এ একটি group action-এর জন্য x ~ y ⇔ “কোনো g-এর জন্য g·x = y” সম্পর্কটি equivalence বলে প্রমাণ হয়েছে (identity থেকে reflexive, উল্টো উপাদান থেকে symmetric, composition থেকে transitive). তার class-ই orbit, আর মৌলিক উপপাদ্য অনুযায়ী orbit-গুলো সেটটিকে ভাগ করে। তাই Burnside-এর lemma আসলে একটি নির্দিষ্ট equivalence-এর class গোনার সূত্র: |X/~| = (1/|G|)∑|Fix(g)|. একই ধাঁচে isomorphism-এর class-ও orbit (vertex-এর নাম বদলানোর group), যা পর্ব ৫৮-এ আসবে।

অঙ্ক ১: Equivalence কি না, আর class

A = {1, 2, 3, 4, 5, 6}-এ a R b ⇔ a + b জোড়। R কি equivalence? class আর জোড়ার সংখ্যা কত?

  1. a + a = 2a জোড়, তাই reflexive. a + b জোড় হলে b + a-ও একই সংখ্যা, তাই symmetric.
  2. a + b আর b + c জোড় হলে (a + b) + (b + c) = a + c + 2b জোড়, তাই a + c জোড়: transitive. সুতরাং equivalence (আসলে a R b ⇔ a ≡ b (mod 2), parity-ফাংশনের kernel).
  3. class: {1, 3, 5} আর {2, 4, 6}; জোড়া 32 + 32 = 18 (scratch-এ গুনে মেলানো)।

অঙ্ক ২: সবচেয়ে ছোট equivalence

A = {1, 2, 3, 4}-এ R = Δ ∪ {(1,2), (2,1), (2,3), (3,2)}. R কি equivalence? না হলে R-কে ধারণকারী সবচেয়ে ছোট equivalence কোনটি?

  1. R reflexive আর symmetric, কিন্তু 1 R 2, 2 R 3 অথচ (1, 3) ∉ R: transitive নয়।
  2. উপপাদ্য ৭.৩: পথ ধরে 1, 2, 3 যুক্ত, 4 একা। তাই class {1, 2, 3} আর {4}; যোগ করতে হয় শুধু (1,3) আর (3,1).
  3. উত্তর: 32 + 12 = 10টি জোড়ার relation (R-এর ৮টি + ২টি)।

অঙ্ক ৩: গোনা

{a, b, c, d}-এ কয়টি equivalence relation? ঠিক দুটি class-যুক্ত কয়টি? উত্তর: B4 = 15; class-এর সংখ্যা অনুযায়ী 1 + 7 + 6 + 1. দুটি class: আকার ৩ + ১ হলে একা উপাদানটি বাছার ৪ উপায়, আর ২ + ২ হলে C(4, 2)/2 = 3 উপায় (দুটি block নামহীন বলে ২ দিয়ে ভাগ), মোট S(4, 2) = 7 (প্রথম Python ব্লকে মেলানো)।

প্রমাণের ভুল ধরুন: “symmetric + transitive ⇒ reflexive”

একজন লিখলেন: “R symmetric আর transitive হলে reflexive-ও। প্রমাণ: যেকোনো a নিন। a R b হলে symmetric ধর্মে b R a. এখন a R b আর b R a থেকে transitive ধর্মে a R a. তাই R reflexive, আর সংজ্ঞা থেকে reflexive শর্তটি বাদ দেওয়া যায়।”

ভুল কোথায়: প্রমাণটি ধরে নিয়েছে যে প্রতিটি a-এর জন্য এমন কোনো b আছে যাতে a R b. সেই b না থাকলে symmetric আর transitive শর্ত দুটি “যদি … তবে” বলে কিছুই দাবি করে না, আর a R a প্রমাণ হয় না। সবচেয়ে ছোট পাল্টা-উদাহরণ: A = {1}-এ খালি relation ∅, যা শূন্যভাবে (vacuously) symmetric আর transitive, কিন্তু 1 R 1 নয়। §১-এর সারণির “ab > 0” আরেকটি: 0-এর কোনো সঙ্গী নেই। সঠিক কথা: symmetric আর transitive R-এ “যার অন্তত একটি সঙ্গী আছে” এমন প্রতিটি a-এর জন্য a R a. নিচের ব্লক ছোট সেটে এমন relation সব গুনে দেখায় যে তারা আসলে বিরল নয়।

from itertools import product
from math import comb

def props(n, R):
    refl = all((a, a) in R for a in range(n))
    sym = all((b, a) in R for a, b in R)
    trans = all((a, d) in R for a, b in R for c, d in R if b == c)
    return refl, sym, trans

bell = [1]
for m in range(5):                    # B(m+1) = sum C(m, k) B(k)
    bell.append(sum(comb(m, k) * bell[k] for k in range(m + 1)))

for n in range(1, 5):
    cells = [(a, b) for a in range(n) for b in range(a, n)]
    st = not_refl = 0                 # symmetric: choose cells with a <= b
    example = None
    for bits in product((0, 1), repeat=len(cells)):
        R = set()
        for (a, b), x in zip(cells, bits):
            if x:
                R |= {(a, b), (b, a)}
        refl, sym, trans = props(n, R)
        if sym and trans:
            st += 1
            if not refl:
                not_refl += 1
                if example is None or len(R) > len(example):
                    example = R
    print(f"n={n}: symmetric+transitive {st:2} (Bell(n+1) = {bell[n + 1]:2}),"
          f" not reflexive {not_refl:2}")
print("largest counterexample for n=4:", sorted(example))

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

n=1: symmetric+transitive  2 (Bell(n+1) =  2), not reflexive  1
n=2: symmetric+transitive  5 (Bell(n+1) =  5), not reflexive  3
n=3: symmetric+transitive 15 (Bell(n+1) = 15), not reflexive 10
n=4: symmetric+transitive 52 (Bell(n+1) = 52), not reflexive 37
largest counterexample for n=4: [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]

৪-উপাদানের সেটে symmetric আর transitive relation ৫২টি, তার ৩৭টিই reflexive নয়, তাই “ভুল উপপাদ্য”টি প্রায় সব ক্ষেত্রেই মিথ্যা। সবচেয়ে বড় পাল্টা-উদাহরণটি দেখুন: {1, 2, 3}-এর ওপর একটি পূর্ণ equivalence, আর 0-এর কোনো সঙ্গী নেই, ঠিক ভুল প্রমাণের ফাঁক। সংখ্যাগুলো Bn+1-এর সঙ্গে মেলে, আর কারণটি সুন্দর: এমন relation মানে “কোন উপাদানগুলো সক্রিয়” বাছাই করে তাদের ওপর একটি equivalence, যা n + 1তম একটি কাল্পনিক উপাদান যোগ করে “নিষ্ক্রিয়দের” তার block-এ রাখার সমান। (এখানে শুধু symmetric relation তালিকা করা হয়েছে, n = 4-এ 210 = 1024টি, কারণ symmetric শর্তটি তো লাগবেই।)

আরও গভীরে: বীজগণিতে বিশেষ গুরুত্ব পায় সেই equivalence, যার সঙ্গে অপারেশন well-defined থাকে; তাকে বলে congruence relation, আর তার quotient থেকেই quotient group আর quotient ring আসে (পর্ব ৭০ “Group — symmetry, cyclic group আর Lagrange-এর উপপাদ্য” আর পর্ব ৭১ “Ring আর field — modular ring, polynomial আর GF(2ⁿ)”)। Automata তত্ত্বে Myhill–Nerode উপপাদ্য (১৯৫০-এর দশকের শেষে) একটি language-এর জন্য string-এর ওপর একটি equivalence সংজ্ঞায়িত করে, আর বলে language-টি regular যদি এবং কেবল যদি তার class সসীম সংখ্যক; class-গুলোই সবচেয়ে ছোট automaton-এর state, যার পরিচয় পর্ব ৭৪ “Finite automaton আর regular expression-এর পরিচয়”-এ, আর বিস্তারিত পরের Theory of Computation কোর্সে আসবে।

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

  • ℤ-এ |a − b| ≤ 1 কি equivalence? না; 0 ~ 1, 1 ~ 2, কিন্তু 0 ≁ 2, transitive নয়।
  • ৪-উপাদানের সেটে কয়টি equivalence relation? B4 = 15.
  • দুটি equivalence class-এর মধ্যে সম্পর্ক কী? হয় সমান, নয়তো বিচ্ছিন্ন (lemma ২.২)।
  • দুটি equivalence-এর union কি equivalence? সবসময় নয়; intersection সবসময় হয়।
  • ৫-উপাদানের সেটে কোনো equivalence-এ কি ঠিক ১০টি জোড়া থাকতে পারে? না; জোড়ার সংখ্যা ∑si2, যার সম্ভাব্য মান 5, 7, 9, 11, 13, 17, 25.

১০ · AI-এর যুগে — equivalence-এর প্রমাণ আর গণনা যাচাই

Relation-এর প্রশ্নে AI সহকারী প্রায়ই সংজ্ঞা নির্ভুল লেখে, কিন্তু প্রয়োগে আত্মবিশ্বাসী ভুল করে। কয়েকটি নিয়মিত ভুল আর ধরার উপায়:

AI-এর ভুলকীভাবে ধরবেন
“symmetric আর transitive হলেই reflexive” ধরনের প্রমাণ, যেখানে একটি সঙ্গীর অস্তিত্ব চুপচাপ ধরে নেওয়াখালি relation বা সঙ্গীহীন উপাদান দিয়ে পরীক্ষা করুন
“কাছাকাছি” ধরনের সম্পর্ককে (দূরত্ব, মিল, similarity score) equivalence বলাতিনটি উপাদানের একটি শৃঙ্খল দিয়ে transitivity পরীক্ষা করুন
Quotient-এর ওপর অপারেশন well-defined কি না না দেখেই ব্যবহারএকই class-এর দুটি আলাদা প্রতিনিধি বসিয়ে ফল মেলান
Equivalence গুনতে 2n, n! বা C(n, 2)-এর মতো ভুল সূত্রn = 3-এ সব ৫১২টি relation গুনে ৫ পান কি না দেখুন
Closure-এর ক্রম উল্টে ফেলা (আগে transitive, পরে symmetric)ফলাফলের ওপর আবার transitive পরীক্ষা চালান

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

নিচের relation-টি equivalence কি না ধাপে ধাপে দেখাও: Relation: [যেমন ℤ × (ℤ − {0})-এ (a, b) ~ (c, d) ⇔ ad = bc] ১. reflexive, symmetric আর transitive তিনটি আলাদা অংশে প্রমাণ করো; প্রতিটি ধাপের পাশে কোন নিয়ম বা শর্ত ব্যবহার হলো তা লেখো। ২. কোথাও শূন্য দিয়ে ভাগ বা বাদ দেওয়া (cancel) হলে স্পষ্ট বলো কোন শর্তে তা বৈধ। ৩. কোনো ধাপে "এমন একটি উপাদান আছে" ধরে নিলে তা আলাদা করে চিহ্নিত করো। ৪. equivalence হলে তিনটি class-এর উদাহরণ দাও; না হলে সবচেয়ে ছোট পাল্টা-উদাহরণ দাও। ৫. ছোট একটি সসীম অংশে তিনটি ধর্ম পরীক্ষার একটি Python কোড দাও (শুধু itertools), যাতে আমি নিজে চালাতে পারি। ৬. কোনো উপপাদ্যের নাম, সাল বা উৎস নিয়ে নিশ্চিত না হলে তা স্পষ্ট বলো।

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

Equivalence-এর প্রশ্নের সুবিধা হলো সসীম অংশে সবকিছু পরীক্ষা করা যায়: ৫ বা ৬টি উপাদানে তিনটি ধর্ম এক মুহূর্তে যাচাই হয়। প্রমাণ সাধারণ ক্ষেত্রে কাজ করে কি না, তা ছোট ক্ষেত্রের পরীক্ষা বলতে পারে না; কিন্তু ভুল প্রমাণ সাধারণত ছোট ক্ষেত্রেই ধরা পড়ে। তাই আগে পাল্টা-উদাহরণ খুঁজুন, তারপর প্রমাণে ভরসা করুন।

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

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

প্র ০১গণিতবিদেরা কীভাবে equivalence class দিয়ে নতুন সংখ্যা “তৈরি” করেন? ℤm, ভগ্নাংশ আর বাস্তব সংখ্যার পেছনের ইতিহাস কী?

Carl Friedrich Gauss ১৮০১ সালে তাঁর Disquisitiones Arithmeticae বইয়ে congruence-এর চিহ্ন a ≡ b (mod m) চালু করেন। তাঁর মূল অন্তর্দৃষ্টি ছিল, বিভাজ্যতার অনেক প্রশ্নে সংখ্যাটি নয়, শুধু তার ভাগশেষ গুরুত্বপূর্ণ। আধুনিক ভাষায় এটি হলো ℤ-কে ≡m দিয়ে ভাগ করে quotient ℤm বানানো, আর যোগ-গুণ যে class-এর ওপর well-defined, সেটিই পুরো তত্ত্বকে বৈধ করে।

ভগ্নাংশও একই পথে আসে। ১/২ আর ২/৪ লেখায় আলাদা, কিন্তু একই সংখ্যা। ℤ × (ℤ − {0})-এ (a, b) ~ (c, d) ⇔ ad = bc একটি equivalence (অনুশীলন ১), আর একটি মূলদ সংখ্যা হলো তার একটি class. যোগ (a, b) + (c, d) = (ad + bc, bd) প্রতিনিধি বদলালেও একই class দেয়, তাই well-defined. এখানে b ≠ 0 শর্তটি বাদ দিলে transitive ধর্ম ভেঙে যায়: (1, 1) ~ (0, 0) আর (0, 0) ~ (2, 1), অথচ (1, 1) ≁ (2, 1).

বাস্তব সংখ্যার নির্মাণে ১৮৭২ সালের কাছাকাছি সময়ে Richard Dedekind (cut দিয়ে) আর Georg Cantor (মূলদ সংখ্যার Cauchy sequence দিয়ে) প্রায় একই সময়ে কাজ করেন বলে জানা যায়। Cantor-এর পথে দুটি sequence “সমতুল্য” যদি তাদের পার্থক্য শূন্যের দিকে যায়, আর একটি বাস্তব সংখ্যা হলো এমন একটি class; যেমন 0.9, 0.99, 0.999, … আর 1, 1, 1, … একই class, যা “0.999… = 1”-এর একটি নির্ভুল ব্যাখ্যা। Gottlob Frege ১৮৮৪ সালের Grundlagen der Arithmetik বইয়ে আরও এক ধাপ এগিয়ে একটি সংখ্যাকে “সমান আকারের (পর্ব ১৮-এর bijection আছে এমন) সব সেটের class” হিসেবে দেখার প্রস্তাব দেন বলে উল্লেখ করা হয়; পরে Russell-এর paradox দেখায় যে “সব সেটের” এমন সংগ্রহ নিয়ে সাবধান হতে হয়।

এই প্রতিটি নির্মাণে দামটি একই: নতুন বস্তুর ওপর প্রতিটি অপারেশন well-defined প্রমাণ করতে হয়। পাঠ্যবইয়ে এই ধাপটি প্রায়ই এক লাইনে সারা হয়, কিন্তু §৫-এর ঘাতের উদাহরণ দেখায় যে এটি সবসময় সত্য নয়।

মূল উপলব্ধি: ℤm, ভগ্নাংশ আর বাস্তব সংখ্যা সবই কোনো সেটের quotient; equivalence দিয়ে “অপ্রাসঙ্গিক পার্থক্য” ভুলে যাওয়া গণিতের নতুন বস্তু বানানোর মূল কৌশল, আর তার শর্ত well-defined অপারেশন।

প্র ০২প্রোগ্রামিং ভাষায় “সমান” (==, equals) কেন equivalence হওয়া উচিত? NaN আর “প্রায় সমান” তুলনা কী সমস্যা করে?

Java-র Object.equals-এর ডকুমেন্টেশন স্পষ্টভাবে বলে, equals হতে হবে reflexive, symmetric আর transitive (সঙ্গে consistent, আর null-এর সঙ্গে false). Python-এর ডকুমেন্টেশন __hash__ নিয়ে বলে, সমান বস্তুর hash মান সমান হতে হবে। §৬-এর ভাষায়: == relation-কে hash ফাংশনের kernel-এর ভেতরে থাকতে হবে (একটি refinement), নইলে dictionary বা set একই key দুবার রাখতে পারে, বা রাখা key খুঁজে পায় না। Python কোর্সের পর্ব ৩২-এ __eq__ আর __hash__ লেখার নিয়ম আছে।

Floating point-এ এই নিয়ম জেনেশুনে ভাঙা হয়েছে। IEEE 754 মানে (প্রথম সংস্করণ ১৯৮৫) NaN (“not a number”) কোনো কিছুর সমান নয়, নিজেরও নয়, তাই float-এর == reflexive নয়। CPython-এর list তুলনা আগে দেখে দুটি বস্তু একই কি না (identity), তারপর == চালায়; তাই একই NaN বস্তু নিয়ে [nan] == [nan] সত্য, যদিও nan == nan মিথ্যা (অনুশীলন ৩)। একটি ভাষার দুই অংশ এখানে relation-এর আলাদা নিয়ম মানছে।

“প্রায় সমান” আরও বড় ফাঁদ। abs(a − b) < ε তুলনাটি reflexive আর symmetric, কিন্তু transitive নয়: 0.0 আর 0.1, 0.1 আর 0.2 “প্রায় সমান” (ε = 0.15), কিন্তু 0.0 আর 0.2 নয়। কেউ যদি এই তুলনা দিয়ে মাপের ডেটাকে “একই মানের দলে” ভাগ করতে চান, তবে ফল নির্ভর করে কোন ক্রমে ডেটা এসেছে তার ওপর, কারণ দলগুলো আসলে partition নয়। নিরাপদ বিকল্প হলো একটি key ফাংশন বানানো, যেমন round(x, 2) বা ⌊x/ε⌋, যার kernel আপনাআপনি equivalence; দাম হলো সীমানার কাছাকাছি দুটি খুব কাছের মান আলাদা দলে পড়তে পারে।

Sorting-এও একই কথা: comparison-ভিত্তিক sort ধরে নেয় তুলনাটি একটি সুসংগত ক্রম দেয়, যার “সমান” অংশ একটি equivalence. এই অনুমান ভাঙলে কিছু ভাষার sort ব্যতিক্রম (exception) ছোড়ে বা অনির্দিষ্ট ফল দেয়।

মূল উপলব্ধি: সফটওয়্যারের “সমান” তুলনা equivalence-এর তিনটি ধর্ম মানবে, এটি hash table আর sort-এর অদৃশ্য চুক্তি; NaN আর ε-তুলনা এই চুক্তি ভাঙে, তাই key ফাংশনের kernel দিয়ে তুলনা লেখা নিরাপদ।

প্র ০৩Union-find কোথা থেকে এলো, এর জটিলতার সীমা কী, আর বাস্তবে গ্রাহকের ডুপ্লিকেট রেকর্ড মেলাতে transitive closure কেন বিপদও ডেকে আনে?

Disjoint-set forest-এর ধারণা Bernard Galler আর Michael Fischer-এর ১৯৬৪ সালের একটি প্রবন্ধের সঙ্গে যুক্ত বলে সাধারণত উল্লেখ করা হয়, যেখানে প্রোগ্রামের ভেতরে কোন চলক একই মেমরি ভাগ করে, সেই equivalence সামলানো দরকার ছিল। Path compression আর union by rank-এর যৌথ বিশ্লেষণে Robert Tarjan ১৯৭৫ সালে O(m α(n)) সীমা প্রমাণ করেন, আর পরে Michael Fredman ও Michael Saks ১৯৮৯ সালে দেখান যে একটি সাধারণ মডেলে এর চেয়ে ভালো করা সম্ভব নয় বলে জানা যায়। α(n) এত ধীরে বাড়ে যে বাস্তবের যেকোনো ইনপুটে তা ৪ বা ৫-এর বেশি হয় না।

সবচেয়ে পরিচিত ব্যবহার Kruskal-এর minimum spanning tree algorithm (১৯৫৬): একটি edge নেওয়ার আগে দেখতে হয় তার দুই প্রান্ত ইতিমধ্যে একই component-এ কি না, অর্থাৎ “একই component” equivalence-এর class (DSA কোর্সের পর্ব ৪৫)। Image processing-এ একই রঙের সংলগ্ন pixel-এর দল খোঁজা, compiler-এ type unification, আর network-এ connectivity, সবখানেই একই কাঠামো।

বাস্তবের রেকর্ড মেলানো (entity resolution) কিন্তু §৮-এর চেয়ে কঠিন। সেখানে “একই গ্রাহক” প্রায়ই কোনো নিখুঁত key থেকে আসে না, আসে similarity score থেকে: নামের বানান প্রায় এক, ঠিকানা কাছাকাছি। Similarity transitive নয়, অথচ union-find তার ওপর transitive closure চাপিয়ে দেয়। ফল হতে পারে “chaining”: A প্রায় B-এর মতো, B প্রায় C-এর মতো, … , আর শেষে সম্পূর্ণ আলাদা দুজন মানুষ এক দলে। একটি ভুল জোড়া দুটি বড় দলকে চিরকালের জন্য জুড়ে দিতে পারে, কারণ union-find-এ “আলাদা করা” কাজ নেই।

তাই বাস্তব ব্যবস্থা সাধারণত দুই স্তরে কাজ করে: নিখুঁত key (যাচাই করা ফোন নম্বর, NID) দিয়ে union-find, আর অনিশ্চিত মিলগুলো মানুষের পর্যালোচনায় বা আরও সতর্ক clustering-এ। গণিতটি এখানে সতর্কসংকেত দেয়: যে সম্পর্ক transitive নয়, তার closure নিলে আপনি মূল দাবির চেয়ে অনেক বেশি দাবি করছেন।

মূল উপলব্ধি: Union-find একটি equivalence closure-কে প্রায় ধ্রুব সময়ে রক্ষা করে; কিন্তু ইনপুট-সম্পর্কটি নিজে transitive না হলে closure ভুল দলও জুড়ে দেয়, আর সেই জোড় পরে খোলা যায় না।

প্র ০৪Kernel উপপাদ্য বলে প্রতিটি equivalence কোনো ফাংশনের “একই মান”। তাহলে কিছু equivalence যাচাই করা সহজ আর কিছু কঠিন কেন? Canonical form কী?

উপপাদ্য ৬.২-এর ফাংশনটি π, যা প্রতিটি উপাদানকে তার class-এ পাঠায়; কিন্তু class-টি হাতে-কলমে লেখা বা হিসাব করা সহজ না-ও হতে পারে। ব্যবহারিক প্রশ্ন হলো: এমন একটি সহজে গণনাযোগ্য ফাংশন f আছে কি, যার kernel ঠিক এই equivalence? থাকলে f(x) হলো x-এর canonical form, আর “x ~ y?” প্রশ্নের উত্তর f(x) == f(y). যেমন দুটি শব্দ anagram কি না (“listen” আর “silent”), তা অক্ষরগুলো সাজিয়ে তুলনা করলেই হয়; একটি necklace-এর canonical form তার সব rotation-এর মধ্যে অভিধান-ক্রমে সবচেয়ে ছোটটি (পর্ব ৫১)।

কেবল একমুখী সংকেত দেয় এমন ফাংশনকে বলে invariant: যার kernel equivalence-কে ধারণ করে, কিন্তু তার চেয়ে বড়। Graph-এর degree sequence একটি invariant: isomorphic graph-এর degree sequence সমান, কিন্তু সমান degree sequence থাকলেও graph isomorphic না-ও হতে পারে। একটি invariant-এর kernel ঠিক equivalence-এর সমান হলে তাকে complete invariant বলে। Graph isomorphism-এর জন্য দ্রুত গণনাযোগ্য complete invariant জানা নেই; László Babai ২০১৫ সালে একটি quasi-polynomial algorithm ঘোষণা করেন, যা এই সমস্যার বড় অগ্রগতি হিসেবে ধরা হয় (পর্ব ৫১-এর আলোচনা আর পর্ব ৫৮ “গ্রাফের representation আর isomorphism”).

একটি সুন্দর উদাহরণ digital circuit-এ। একটি finite state machine-এর দুটি state “সমতুল্য” যদি যেকোনো input-ধারায় একই output দেয়। এই equivalence-এর class খুঁজতে partition refinement ব্যবহার হয়: শুরুতে output অনুযায়ী মোটা ভাগ, তারপর বারবার এমন block ভাঙা, যার সদস্যরা কোনো input-এ ভিন্ন block-এ যায়। কোনো block আর না ভাঙলে প্রতিটি block একটি state হয়ে সবচেয়ে ছোট machine দেয়। Computer Architecture কোর্সের পর্ব ১৭-এ state machine নকশায় এর ব্যবহার আছে, আর John Hopcroft-এর ১৯৭১ সালের algorithm এই কাজ n log n-এর কাছাকাছি সময়ে করে বলে জানা যায়।

বাজারঘরের ক্ষেত্রেও প্রশ্নটি একই: email-কে ছোট হাতের অক্ষরে রূপান্তর একটি canonical form, ফলে “একই email” যাচাই সহজ; কিন্তু “একই মানুষ” যাচাইয়ের কোনো নিখুঁত canonical form নেই, তাই প্র ০৩-এর সমস্যা।

মূল উপলব্ধি: প্রতিটি equivalence কোনো ফাংশনের kernel, কিন্তু সেই ফাংশন দ্রুত গণনাযোগ্য হলে (canonical form) যাচাই সহজ, না হলে কঠিন; invariant শুধু “আলাদা” প্রমাণ করতে পারে, “একই” নয়।

প্র ০৫Bell সংখ্যা কত দ্রুত বাড়ে, এর পেছনে কোন পুরোনো ইতিহাস আছে, আর data clustering-এ এর অর্থ কী?

Bell সংখ্যা 1, 1, 2, 5, 15, 52, 203, 877, 4140, … দ্রুত বাড়ে: B10 = 115975, আর বৃদ্ধি exponential-এর চেয়েও দ্রুত, যদিও n!-এর চেয়ে ধীরে। নামটি Eric Temple Bell-এর, যিনি ১৯৩০-এর দশকে এদের নিয়ে লেখেন বলে জানা যায়; তবে সংখ্যাগুলো অনেক আগেই জানা ছিল। একটি প্রায়ই উল্লেখিত উদাহরণ জাপানের Genji-kō নামের সুগন্ধি-খেলা: পাঁচটি ধূপ পোড়ানো হয়, অংশগ্রহণকারীরা অনুমান করেন কোনগুলো একই সুগন্ধ, আর সম্ভাব্য প্রতিটি দলভাগের জন্য একটি প্রতীক ছিল। প্রতীক ঠিক ৫২টি, যা B5; Donald Knuth তাঁর বইয়ে এই প্রতীকগুলোর কথা লিখেছেন বলে উল্লেখ করা হয়।

Data clustering মানে আসলে একটি partition বেছে নেওয়া: গ্রাহকদের কয়েকটি দলে ভাগ করা, যাতে এক দলের সদস্যরা কাছাকাছি। প্রতিটি clustering একটি equivalence (“একই দলে”)। কিন্তু সম্ভাব্য partition Bnটি; মাত্র ২০ জন গ্রাহকে B20 প্রায় ৫ × ১০13 (৫১,৭২৪,১৫৮,২৩৫,৩৭২), তাই সব partition পরীক্ষা করে সেরাটি বাছা অসম্ভব। ঠিক k-টি দলে ভাগ চাইলেও S(n, k)টি সম্ভাবনা। এজন্য k-means বা hierarchical clustering-এর মতো algorithm একটি ভালো (সবচেয়ে ভালো নয়) partition খোঁজে।

দুটি clustering কতটা মেলে, তা মাপতেও equivalence-এর ভাষা লাগে। একটি পরিচিত মাপ (William Rand-এর ১৯৭১ সালের প্রবন্ধের সঙ্গে যুক্ত Rand index) সব উপাদান-জোড়া দেখে: দুই clustering-এ জোড়াটি “একই দলে / আলাদা দলে” প্রশ্নে কতবার একমত। অর্থাৎ এটি দুটি equivalence relation-এর matrix ঘর ধরে তুলনা। Hierarchical clustering-এর ফল একটি refinement-এর শৃঙ্খল: সূক্ষ্মতম partition (সবাই একা) থেকে ধাপে ধাপে block জুড়ে শেষে একটি block, ঠিক §৮-এর union-find-এর মতো।

মূল উপলব্ধি: n উপাদানের দলভাগ Bnটি, যা বিস্ফোরকভাবে বাড়ে; তাই clustering-এ সব partition দেখা অসম্ভব, আর সেই কারণে heuristic algorithm লাগে, যদিও তাদের ফল প্রতিবার একটি equivalence relation.

অনুশীলন

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

  1. প্রমাণ: ℤ × (ℤ − {0})-এ (a, b) ~ (c, d) ⇔ ad = bc. প্রমাণ করুন ~ একটি equivalence relation, আর দেখান দ্বিতীয় স্থানাঙ্কে 0 অনুমতি দিলে কোন ধর্মটি ভাঙে।
    1. Reflexive: ab = ba, তাই (a, b) ~ (a, b). — গুণের বিনিময় নিয়ম
    2. Symmetric: ad = bc হলে cb = da, অর্থাৎ (c, d) ~ (a, b). — সমতার দুই পাশ অদলবদল
    3. Transitive: ad = bc আর cf = de ধরুন। প্রথমটিকে f দিয়ে গুণ: adf = bcf = b(cf) = bde. তাই d(af − be) = 0. — দ্বিতীয় সমীকরণ বসানো
    4. d ≠ 0, আর ℤ-এ দুটি অশূন্য সংখ্যার গুণফল অশূন্য, তাই af − be = 0, অর্থাৎ (a, b) ~ (e, f). ∎ — d ≠ 0 শর্ত এখানেই লাগে

    দ্বিতীয় স্থানাঙ্কে 0 চললে: (1, 1) ~ (0, 0) (1 · 0 = 1 · 0) আর (0, 0) ~ (2, 1) (0 · 1 = 0 · 2), কিন্তু (1, 1) ≁ (2, 1), কারণ 1 · 1 ≠ 1 · 2. Transitive ভাঙে, ঠিক ধাপ ৪-এর জায়গায় (scratch-এ ছোট পরিসরে সব ত্রয়ী পরীক্ষা করে মেলানো)। class-গুলোই মূলদ সংখ্যা: (1, 2), (2, 4), (−3, −6) একই class.

  2. হিসাব: A = {1, 2, 3, 4, 5}. (ক) A-তে ঠিক ৩টি class-যুক্ত equivalence কয়টি? (খ) কয়টি equivalence-এ 1 আর 2 একই class-এ? (গ) A-তে এমন equivalence আছে কি, যার relation-এ ঠিক ১০টি ক্রমজোড়া?

    (ক) S(5, 3) = 25. হাতে: block-এর আকার ৩+১+১ হলে C(5, 3) = 10 উপায়; ২+২+১ হলে একা উপাদানটি ৫ উপায়ে, বাকি চারটিকে দুই জোড়ায় 3 উপায়ে, মোট 15. যোগফল 25 (প্রথম Python ব্লকের n = 5 সারি)।

    (খ) 1 আর 2-কে একটি উপাদান হিসেবে জুড়ে দিলে ৪টি “উপাদান”-এর partition: B4 = 15.

    (গ) না। জোড়ার সংখ্যা ∑si2, যেখানে si block-এর আকার আর ∑si = 5. সম্ভাব্য আকার-ভাগ: 5 → 25; 4+1 → 17; 3+2 → 13; 3+1+1 → 11; 2+2+1 → 9; 2+1+1+1 → 7; 1+1+1+1+1 → 5. ১০ তালিকায় নেই। আরও দ্রুত যুক্তি: s2 আর s-এর parity এক, তাই ∑si2-এর parity ∑si = 5-এর মতো বিজোড়; ১০ জোড়, তাই অসম্ভব (scratch-এ সব partition থেকে মেলানো)।

  3. আউটপুট অনুমান: কোড না চালিয়ে বলুন কী ছাপা হবে, আর প্রতিটি লাইন equivalence-এর কোন ধর্ম সম্পর্কে কী বলে। তারপর যেকোনো Python-এ চালিয়ে মেলান।
    close = lambda a, b: abs(a - b) < 0.15
    print(close(0.0, 0.1), close(0.1, 0.2), close(0.0, 0.2))
    nan = float("nan")
    print(nan == nan, [nan] == [nan])
    True True False
    False True

    প্রথম লাইন: “প্রায় সমান” তুলনা transitive নয়; 0.0 ≈ 0.1 আর 0.1 ≈ 0.2, কিন্তু 0.0 ≉ 0.2. দ্বিতীয় লাইন: IEEE 754 অনুযায়ী NaN নিজের সমানও নয়, তাই float-এর == reflexive নয়। অথচ list তুলনায় CPython আগে দেখে দুটি উপাদান একই বস্তু কি না, আর একই বস্তু হলে == না চালিয়েই সমান ধরে, তাই [nan] == [nan] হলো True. আউটপুট CPython 3.14-এ চালিয়ে মেলানো।

  4. প্রমাণের ভুল ধরুন: একজন লিখলেন: “R-কে ধারণকারী সবচেয়ে ছোট equivalence পেতে আগে reflexive closure, তারপর transitive closure, শেষে symmetric closure নিলেই হয়, কারণ তিনটি ধর্মই যোগ হলো।” A = {1, 2, 3} আর R = {(1, 2), (3, 2)} দিয়ে দাবিটি পরীক্ষা করুন। ভুল কোথায়, আর সঠিক ক্রম কী?
    • হিসাব: reflexive closure: R ∪ {(1,1), (2,2), (3,3)}. Transitive closure: নতুন কিছু আসে না, কারণ 2 থেকে নিজের ছাড়া কোথাও যাওয়ার জোড়া নেই। Symmetric closure: (2,1) আর (3,2)-এর উল্টো (2,3) যোগ। ফল {(1,1), (1,2), (2,1), (2,2), (2,3), (3,2), (3,3)}, ৭টি জোড়া।
    • ভুল ধাপ: ফলটিতে 1 ~ 2 আর 2 ~ 3, কিন্তু (1, 3) নেই: transitive নয়। শেষে symmetric closure নতুন জোড়া যোগ করে, আর সেই নতুন জোড়াগুলো নতুন শৃঙ্খল তৈরি করতে পারে, যা আগের transitive ধাপ দেখেনি। “তিনটি ধর্ম একবার করে যোগ করা হয়েছে” মানে এই নয় যে শেষেও তিনটি টিকে আছে।
    • সংশোধন: উপপাদ্য ৭.৩-এর ক্রম: আগে reflexive আর symmetric, শেষে transitive. তখন ফল A × A, ৯টি জোড়া, একটি class {1, 2, 3}. Transitive closure symmetric-কে নষ্ট করে না (উপপাদ্য ৭.৩-এর ধাপ ৩), কিন্তু symmetric closure transitive-কে নষ্ট করতে পারে (scratch-এ দুই ক্রমেই হিসাব করে মেলানো)।

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

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

ক্রম“একটি equivalence-এর class-গুলো সেটটির partition” প্রমাণের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Reflexive ধর্ম থেকে a ∈ [a], তাই প্রতিটি class খালি নয় আর সবাই কোনো class-এ আছে
  2. a ~ b হলে transitive আর symmetric ধর্মে [a] = [b] দেখানো
  3. [a] ∩ [b]-এ একটি সাধারণ সদস্য c থাকলে c-এর মাধ্যমে a ~ b দেখানো
  4. তাই দুটি class হয় সমান, নয়তো বিচ্ছিন্ন
  5. সিদ্ধান্ত: আলাদা class-গুলো খালি নয়, বিচ্ছিন্ন, আর মিলে পুরো সেট, অর্থাৎ partition

৪-উপাদানের একটি সেট {a, b, c, d}-এর ওপর কয়টি আলাদা equivalence relation আছে?

  • 16
  • 15
  • 24
  • 7

পূর্ণসংখ্যার সেট ℤ-এ নিচের কোন relation equivalence relation নয়?

  • a ~ b ⇔ 7 ∣ a − b
  • a ~ b ⇔ |a| = |b|
  • a ~ b ⇔ |a − b| ≤ 1
  • a ~ b ⇔ a² = b²

একটি সেটের ওপর দুটি equivalence relation R আর S দেওয়া আছে। নিচের কোন কথাটি সবসময় সত্য?

  • R ∩ S একটি equivalence relation
  • R ∪ S একটি equivalence relation
  • R − S একটি equivalence relation
  • R ∩ S-এর class আর R-এর class সবসময় একই

৫-উপাদানের একটি সেটের ওপর একটি equivalence relation-এ (ক্রমজোড়ার সেট হিসেবে) কয়টি জোড়া থাকা অসম্ভব?

  • 9
  • 13
  • 5
  • 10

Union-find-এ find(x) চলার সময় path compression পথের node-গুলোকে সরাসরি root-এর নিচে বসায়। এতে কী বদলায়?

  • দুটি class একটিতে মিশে যায়
  • শুধু tree-র আকৃতি; কোন উপাদান কোন class-এ তা বদলায় না
  • class-এর প্রতিনিধি (root) বদলে যায়
  • একটি class দুই ভাগ হয়ে যায়

a ∈ ℤ-এর জন্য নিয়ম F([a]m) = [a]n. নিচের কোন জোড়া (m, n)-এর জন্য F well-defined?

  • m = 6, n = 4
  • m = 4, n = 12
  • m = 12, n = 4
  • m = 10, n = 3

শব্দকোষ

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

মনে রাখুন

  1. সংজ্ঞা: equivalence = reflexive (প্রতিটি a-তে a ~ a) + symmetric + transitive; “কাছাকাছি” ধরনের সম্পর্ক সাধারণত transitive নয়।
  2. মৌলিক উপপাদ্য: দুটি class হয় সমান, নয়তো বিচ্ছিন্ন; class-গুলো একটি partition, আর equivalence ↔ partition একটি bijection.
  3. গণনা: n উপাদানে Bnটি equivalence, k-টি class-এ S(n, k); class-এর আকার si হলে জোড়া ∑si2.
  4. Quotient আর kernel: A/~-এর ওপর অপারেশন চাইলে well-defined প্রমাণ জরুরি; প্রতিটি equivalence কোনো ফাংশনের kernel, আর f = ι ∘ f̄ ∘ π.
  5. Closure আর union-find: intersection equivalence, union নয়; সবচেয়ে ছোট equivalence = (R ∪ Δ ∪ R−1)*, আর union-find “একই root” রেখে সেটিই রক্ষা করে।

পরের পর্বে: পর্ব ৫৬ “Partial order, Hasse diagram, topological sort আর lattice”: symmetric-এর জায়গায় antisymmetric শর্ত নিলে “একই রকম”-এর বদলে “আগে-পরে” বা “ছোট-বড়” সম্পর্ক পাওয়া যায়, আর বাজারঘরের কাজগুলো সঠিক ক্রমে সাজানোর গণিত শুরু হবে।

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

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