প্রিমিটিভ রুট#

সংজ্ঞা#

মডুলার পাটিগণিতে, একটি সংখ্যা $g$ কে n এর মডুলোতে প্রিমিটিভ রুট বলা হয় যদি $n$ এর সাথে সহমৌলিক প্রতিটি সংখ্যা $g$ এর কোনো ঘাতের সাথে $n$ মডুলোতে সর্বসম হয়। গাণিতিকভাবে, $g$ হলো n এর মডুলোতে প্রিমিটিভ রুট যদি এবং কেবলমাত্র যদি যেকোনো পূর্ণ সংখ্যা $a$ এর জন্য যেখানে $\gcd(a, n) = 1$, এমন একটি পূর্ণ সংখ্যা $k$ থাকে যেন:

$g^k \equiv a \pmod n$

$k$ কে তখন $g$ ভিত্তিক $a$ এর ইনডেক্স বা ডিসক্রিট লগারিদম বলা হয় $n$ মডুলোতে। $g$ কে $n$ মডুলোতে পূর্ণ সংখ্যাদের গুণন গ্রুপের জেনারেটর-ও বলা হয়।

বিশেষত, $n$ মৌলিক সংখ্যা হলে, প্রিমিটিভ রুটের ঘাতগুলো $1$ থেকে $n-1$ পর্যন্ত সব সংখ্যার মধ্য দিয়ে যায়।

অস্তিত্ব#

$n$ এর মডুলোতে প্রিমিটিভ রুট থাকে যদি এবং কেবলমাত্র যদি:

  • $n$ হলো ১, ২, ৪, অথবা
  • $n$ হলো একটি বিজোড় মৌলিক সংখ্যার ঘাত $(n = p^k)$, অথবা
  • $n$ হলো একটি বিজোড় মৌলিক সংখ্যার ঘাতের দ্বিগুণ $(n = 2 \cdot p^k)$।

এই উপপাদ্যটি গাউস ১৮০১ সালে প্রমাণ করেছিলেন।

অয়লার ফাংশনের সাথে সম্পর্ক#

ধরি $g$ হলো $n$ এর মডুলোতে একটি প্রিমিটিভ রুট। তাহলে আমরা দেখাতে পারি যে ক্ষুদ্রতম সংখ্যা $k$ যার জন্য $g^k \equiv 1 \pmod n$ সেটি হলো $\phi (n)$। তাছাড়া, উল্টোটাও সত্য, এবং এই তথ্যটি এই নিবন্ধে প্রিমিটিভ রুট খুঁজতে ব্যবহৃত হবে।

এছাড়াও, $n$ এর মডুলোতে প্রিমিটিভ রুটের সংখ্যা, যদি কোনোটি থাকে, $\phi (\phi (n) )$ এর সমান।

প্রিমিটিভ রুট খোঁজার অ্যালগরিদম#

একটি সরল অ্যালগরিদম হলো $[1, n-1]$ রেঞ্জের সব সংখ্যা বিবেচনা করা। এবং তারপর প্রতিটি সংখ্যা প্রিমিটিভ রুট কিনা তা পরীক্ষা করা, এর সব ঘাত হিসাব করে দেখা যে সেগুলো সব আলাদা কিনা। এই অ্যালগরিদমের কমপ্লেক্সিটি $O(g \cdot n)$, যা অনেক ধীর হবে। এই বিভাগে আমরা বেশ কিছু সুপরিচিত উপপাদ্য ব্যবহার করে একটি দ্রুততর অ্যালগরিদম প্রস্তাব করছি।

আগের বিভাগ থেকে আমরা জানি যে যদি ক্ষুদ্রতম সংখ্যা $k$ যার জন্য $g^k \equiv 1 \pmod n$ সেটি $\phi (n)$ হয়, তাহলে $g$ একটি প্রিমিটিভ রুট। যেহেতু $n$ এর সাথে সহমৌলিক যেকোনো সংখ্যা $a$ এর জন্য, অয়লারের উপপাদ্য থেকে আমরা জানি যে $a ^ { \phi (n) } \equiv 1 \pmod n$, তাই $g$ প্রিমিটিভ রুট কিনা পরীক্ষা করতে, $\phi (n)$ এর চেয়ে ছোট সব $d$ এর জন্য পরীক্ষা করা যথেষ্ট যে $g^d \not \equiv 1 \pmod n$। তবে, এই অ্যালগরিদমও এখনো অনেক ধীর।

ল্যাগ্রাঞ্জের উপপাদ্য থেকে আমরা জানি যে $n$ মডুলোতে যেকোনো সংখ্যার ১ এর ইনডেক্স অবশ্যই $\phi (n)$ এর একটি ভাজক হতে হবে। সুতরাং, $\phi (n)$ এর সব প্রকৃত ভাজক $d \mid \phi (n)$ এর জন্য পরীক্ষা করাই যথেষ্ট যে $g^d \not \equiv 1 \pmod n$। এটি ইতিমধ্যে অনেক দ্রুত অ্যালগরিদম, কিন্তু আমরা আরো ভালো করতে পারি।

$\phi (n) = p_1 ^ {a_1} \cdots p_s ^ {a_s}$ উৎপাদক বিভাজন করি। আমরা প্রমাণ করি যে পূর্ববর্তী অ্যালগরিদমে, শুধুমাত্র $\frac { \phi (n) } {p_j}$ আকারের $d$ এর মানগুলো বিবেচনা করাই যথেষ্ট। প্রকৃতপক্ষে, ধরি $d$ হলো $\phi (n)$ এর যেকোনো প্রকৃত ভাজক। তাহলে, স্পষ্টতই, এমন $j$ আছে যেন $d \mid \frac { \phi (n) } {p_j}$, অর্থাৎ $d \cdot k = \frac { \phi (n) } {p_j}$। তবে, যদি $g^d \equiv 1 \pmod n$ হয়, তাহলে আমরা পাবো:

$g ^ { \frac { \phi (n)} {p_j} } \equiv g ^ {d \cdot k} \equiv (g^d) ^k \equiv 1^k \equiv 1 \pmod n$

অর্থাৎ $\frac {\phi (n)} {p_i}$ আকারের সংখ্যাগুলোর মধ্যে অন্তত একটি থাকবে যেখানে শর্ত পূরণ হবে না।

এখন আমাদের কাছে প্রিমিটিভ রুট খোঁজার একটি সম্পূর্ণ অ্যালগরিদম আছে:

  • প্রথমে, $\phi (n)$ বের করুন এবং এর উৎপাদক বিভাজন করুন।

  • তারপর $g \in [1, n]$ এর সব সংখ্যার মধ্য দিয়ে যান, এবং প্রতিটি সংখ্যার জন্য, এটি প্রিমিটিভ রুট কিনা পরীক্ষা করতে, আমরা নিচের কাজটি করি:

    • সব $g ^ { \frac {\phi (n)} {p_i}} \pmod n$ হিসাব করুন।
    • যদি সব হিসাবকৃত মান $1$ থেকে ভিন্ন হয়, তাহলে $g$ একটি প্রিমিটিভ রুট।

    এই অ্যালগরিদমের রানটাইম হলো $O(Ans \cdot \log \phi (n) \cdot \log n)$ (ধরে নিচ্ছি $\phi (n)$ এর $\log \phi (n)$ টি ভাজক আছে)।

Shoup (১৯৯০, ১৯৯২) প্রমাণ করেছেন, সাধারণীকৃত রিম্যান অনুমান ধরে নিয়ে, $g$ হলো $O(\log^6 p)$।

ইমপ্লিমেন্টেশন#

নিচের কোড ধরে নেয় যে মডুলো p একটি মৌলিক সংখ্যা। যেকোনো p এর মানের জন্য এটি কাজ করাতে, $\phi (p)$ এর হিসাব যোগ করতে হবে।

int powmod (int a, int b, int p) {
	int res = 1;
	while (b)
		if (b & 1)
			res = int (res * 1ll * a % p),  --b;
		else
			a = int (a * 1ll * a % p),  b >>= 1;
	return res;
}

int generator (int p) {
	vector<int> fact;
	int phi = p-1,  n = phi;
	for (int i=2; i*i<=n; ++i)
		if (n % i == 0) {
			fact.push_back (i);
			while (n % i == 0)
				n /= i;
		}
	if (n > 1)
		fact.push_back (n);

	for (int res=2; res<=p; ++res) {
		bool ok = true;
		for (size_t i=0; i<fact.size() && ok; ++i)
			ok &= powmod (res, phi / fact[i], p) != 1;
		if (ok)  return res;
	}
	return -1;
}