কাক ক্যাব

কাক ক্যাব

লার্নিং অনুশীলনী

ভূমিকা

Complex numbers জটিল নয়। এদের শুধু একটা কম ভয়ের নাম দরকার।

এগুলো এতটাই কাজের, বিশেষ করে ইঞ্জিনিয়ারিং আর বিজ্ঞানে, যে R জটিল সংখ্যাকে integer, double, logical, character ও raw-এর পাশাপাশি একটা স্ট্যান্ডার্ড অ্যাটমিক টাইপ হিসেবেও রেখে দিয়েছে।

মূল বিষয়

R-এ একটি complex সংখ্যা আসলে একটি একক মান। তবে ব্যবহারের সময় এটাকে এক জোড়া সংখ্যা হিসেবেও ভাবা যায়। দুর্ভাগ্যজনক ঐতিহাসিক কারণে এদের বলা হয় "বাস্তব" ও "কাল্পনিক" অংশ। আবারও বলি, অদ্ভুত নামগুলো নিয়ে না ভেবে ভেতরের সরলতাটুকুতে মনোযোগ দেওয়াই ভালো।

দুটি বাস্তব সংখ্যা থেকে জটিল সংখ্যা বানাতে চাইলে কাল্পনিক অংশের শেষে শুধু i যোগ করলেই হয়।

2+3i
#> [1] 2+3i

typeof(2+3i)
#> [1] "complex"

বাস্তব ভ্যারিয়েবল থেকে জটিল সংখ্যা বানাতে গেলে উপরের সিনট্যাক্সটা কাজ করবে না। r + imi লিখলে পার্সার বিভ্রান্ত হয়ে ভাবে imi নাকি একটা (অস্তিত্বহীন) ভ্যারিয়েবলের নাম।

তাহলে হয় কাল্পনিক অংশটিকে 1i দিয়ে গুণ করুন, নয়তো [complex()][ref-complex] ফাংশনটি ব্যবহার করুন:

r <- 2
im <- 3

r + im * 1i
#> [1] 2+3i

# must include the `real` and `imaginary` keywords
complex(real = r, imaginary = im)
#> [1] 2+3i

আপনার মনে প্রশ্ন আসতে পারে, j-এর বদলে i কেন?

বেশিরভাগ ইঞ্জিনিয়ার j পছন্দ করেন। বেশিরভাগ বিজ্ঞানী আর গণিতবিদ কাল্পনিক-এর জন্য i গাণিতিক প্রতীকটি পছন্দ করেন, কিন্তু ইলেকট্রিক্যাল ইঞ্জিনিয়ারিংয়ে কারেন্ট বোঝাতে i ব্যবহারের সঙ্গে ওই প্রতীকটির সংঘর্ষ বাধে। R বেছেছে i, Python বেছেছে j, আর Julia বিতর্কটা এড়াতে গিয়ে বেছেছে im। [STEM][wiki-STEM] প্রোগ্রামিং ভাষার মধ্যে যাওয়া-আসা করার সময় সাবধানে থাকুন।

জটিল সংখ্যার অংশগুলো আলাদা আলাদা করে পেতে চাইলে:

z <- 2+3i

Re(z)  # real part
#> [1] 2

Im(z)  # imaginary part
#> [1] 3

যেকোনো একটি অংশ শূন্য হতে পারে, তখন গণিতবিদেরা সংখ্যাটিকে "সম্পূর্ণ বাস্তব" বা "সম্পূর্ণ কাল্পনিক" বলতে পারেন। তবুও R-এ এটা জটিল সংখ্যাই থাকে।

1.2 + 0i
#> [1] 1.2+0i

typeof(1.2 + 0i)
#> [1] "complex"

2i
#> [1] 0+2i

typeof(2i)
#> [1] "complex"

আপনি হয়তো শুনেছেন যে "i (বা j) হলো -1-এর বর্গমূল"।

আপাতত এর মানে শুধু এইটুকু, কাল্পনিক অংশটি সংজ্ঞা অনুযায়ী নিচের সমতাটি মেনে চলে:

1i * 1i == -1  # more precisely, 1i * 1i == -1 + 0i
#> [1] TRUE

ধারণাটা সরল, কিন্তু এর থেকে মজার সব পরিণতি আসে।

পাটিগণিত

ফ্লোট আর ইন্টিজারের সঙ্গে যে অপারেটরগুলো ব্যবহার করা হয়, তার বেশিরভাগই জটিল সংখ্যার ক্ষেত্রেও কাজ করে:

z1 = 1.5 + 2i
z2 = 2 + 1.5i

z1 + z2  # addition
#> [1] 3.5+3.5i

z1 * z2  # multiplication
#> [1] 0+6.25i

z1 / z2  # division
#> [1] 0.96+0.28i

z1^2  # exponentiation
#> [1] -1.75+6i

2^z1  # another exponentiation
#> [1] 0.518895+2.780422i

ফাংশন

বেশিরভাগ গাণিতিক ফাংশনই জটিল ইনপুট নিয়ে কাজ করে।

Re() আর Im() ছাড়াও আরও কিছু ফাংশন আছে, যেগুলোর জটিল সংখ্যার ক্ষেত্রে বিশেষ প্রাসঙ্গিকতা রয়েছে।

  • Conj() জটিল সংখ্যার কাল্পনিক অংশের চিহ্নটা কেবল উল্টে দেয় (+ থেকে - বা উল্টোটাও)।
    • জটিল সংখ্যার গুণ কীভাবে কাজ করে, তার কারণে এটা আপনার ধারণার চেয়েও বেশি কাজের।
  • abs(<complex number>) নিশ্চিতভাবে একটি বাস্তব সংখ্যা রিটার্ন করে, যার কোনো কাল্পনিক অংশ থাকে না (এটার "পরম মান"), আর Mod(<complex number>) এর প্রতিশব্দ।
  • Arg(<complex number>) রেডিয়ানে ফেজ কোণ রিটার্ন করে।
z1
#> [1] 1.5+2i

abs(z1)
#> [1] 2.5

Mod(z1)  # same as previous
#> [1] 2.5

Conj(z1)  # flip sign
#> [1] 1.5-2i

Arg(z1)
#> [1] 0.9272952

নির্দেশনা

আপনাকে এইমাত্র একটি নতুন ক্যাব সার্ভিসে নিয়োগ করা হয়েছে, যেটি ইতিমধ্যেই প্রতিযোগিতায় ভরপুর একটি বাজারে অন্য সেবাগুলো থেকে নিজেকে আলাদা করতে চাইছে। সেটি করতে CEO সিদ্ধান্ত নিয়েছেন যে ম্যানহাটনে একটি অতি-বিলাসবহুল সার্ভিস চালু করবেন, যেখানে প্রতিটি ছেদবিন্দুতে সহকারীরা থাকবেন এবং যাত্রার আগে ও পরে গ্রাহকদের সহায়তা করবেন। এখন আপনাকে এমন কিছু কোড লিখতে হবে, যা এই সার্ভিসের পরিচালনায় সাহায্য করবে।

1. সরল জটিল সংখ্যা

আপনার CEO সিদ্ধান্ত নিয়েছেন যে ম্যানহাটনের রাস্তাগুলো মূলত গ্রিডের মতো সাজানো, তাই জটিল সংখ্যা দিয়ে রাস্তার ছেদবিন্দুগুলো সুবিধাজনকভাবে প্রকাশ করা যায়। এতে ধনাত্মক ও ঋণাত্মক বাস্তব সংখ্যা যথাক্রমে পূর্ব ও পশ্চিম নির্দেশ করে, আর ধনাত্মক ও ঋণাত্মক কাল্পনিক সংখ্যা যথাক্রমে উত্তর ও দক্ষিণ নির্দেশ করে।

যেহেতু R-এ একটি জটিল সংখ্যা ইনস্ট্যানশিয়েট করা একটু, উম... আলাদা ধরনের কাজ, তাই আপনাকে একটি সরল জটিল-সংখ্যা ফাংশন ইমপ্লিমেন্ট করার নির্দেশ দেওয়া হয়েছে।

simplex(a, b) ফাংশনটি ইমপ্লিমেন্ট করুন, যেটি ইন্টিজার a এবং b নেয়। জটিল সংখ্যা a+bi রিটার্ন করুন।

simplex(1, 1)
#> 1+1i

simplex(-3, 4)
#> -3+4i

2. ড্রাইভারের দিকনির্দেশ বের করুন

কোনো গ্রাহক গন্তব্যের ছেদবিন্দু জানালে আপনার ড্রাইভাররা সেখানে পৌঁছানোর দিকনির্দেশ পাবেন। এই দিকনির্দেশ আসে একটি জটিল সংখ্যার আকারে, যার বাস্তব অংশ বোঝায় উত্তর/দক্ষিণে কত ব্লক যেতে হবে এবং কাল্পনিক অংশ বোঝায় পূর্ব/পশ্চিমের দূরত্ব। প্রচলিত কম্পাসের সাথে মিল রাখতে আপনার প্রজেক্ট ম্যানেজার সিদ্ধান্ত নিয়েছেন যে উত্তর থাকবে ধনাত্মক কাল্পনিক দিকে, আর দক্ষিণ থাকবে ঋণাত্মক কাল্পনিক দিকে। একইভাবে পূর্ব থাকবে ধনাত্মক বাস্তব দিকে, আর পশ্চিম থাকবে ঋণাত্মক বাস্তব দিকে।

driver_directions(start, end) ফাংশনটি ইমপ্লিমেন্ট করুন, যেটি start ছেদবিন্দুর স্থানাঙ্ক এবং end গন্তব্যের স্থানাঙ্ক নেয়। এমন একটি জটিল সংখ্যা রিটার্ন করুন যা বোঝায় ড্রাইভারকে পূর্ব/পশ্চিম + উত্তর/দক্ষিণে কত ব্লক যেতে হবে।

driver_directions(0+0i, 7+5i)
#> 7+5i

driver_directions(-2+3i, 4-5i)
#> 6-8i

3. ম্যানহাটন দূরত্ব বের করুন

ক্যাবকে যে দূরত্ব পাড়ি দিতে হবে, তার জন্য গ্রাহকের কাছ থেকে একটি ফি নেওয়া হয়। ম্যানহাটনের রাস্তাগুলো গ্রিডের মতো সাজানো হওয়ায় ট্যাক্সিগুলো কেবল এই পথ ধরেই চলতে পারে। এই গঠনের ফলে দূরত্ব মাপার যে পদ্ধতি দাঁড়ায়, তা গ্রিড রেখাগুলো ধরেই চলতে বাধ্য। পাড়ি দেওয়া রেখার সংখ্যা, কিংবা পৌঁছানো ছেদবিন্দুর সংখ্যা (অর্থাৎ শুরুর ছেদবিন্দুটি বাদ দিয়ে) যোগ করে দূরত্বটি বের করা যায়। এই পরিমাপকেই সাধারণত ম্যানহাটন দূরত্ব বা L1 নর্ম বলা হয়।

manhattan(start, end) ফাংশনটি ইমপ্লিমেন্ট করুন, যেটি start এবং end ছেদবিন্দু নেয়। start ও end ছেদবিন্দুর মধ্যেকার ম্যানহাটন দূরত্ব রিটার্ন করুন।

manhattan(0+0i, 3+4i)
#> 7

manhattan(-2-3i, -1+1i)
#> 5

4. "কাকের মতো সোজা" দূরত্ব বের করুন

CEO ইনভেস্টমেন্ট ব্যাংকগুলোর সম্মতি পেয়ে গেছেন এই কথা তুলে ধরে যে সার্ভিসটি কেবল অতি-বিলাসবহুল নয়, পরিবেশবান্ধবও, কারণ এটি প্রশিক্ষিত কাক ব্যবহার করবে ছেদবিন্দুগুলোর সহকারীদের মধ্যে বার্তা পৌঁছে দেওয়ার জন্য (যারা ব্যক্তিগতকৃত অভিজ্ঞতার জন্য যাত্রীদের সম্পর্কে তথ্য এগিয়ে দেয়)। দেখে মনে হচ্ছে, ইনভেস্টমেন্ট ব্যাংকারদের কেউই কষ্ট করে খোঁজ নেওয়ার ঝামেলা নেয়নি যে এটা ঠিক কীভাবে পরিবেশবান্ধব, বা কেমন ধরনের CEO-ই বা অবসর সময়ে কাক প্রশিক্ষণ দিতে ভালোবাসেন, কারণ বিনিয়োগের টাকা তো ঢলেই আসছে।

এই সার্ভিসেরও ভাড়া নেওয়া হয় অতিক্রান্ত দূরত্ব অনুযায়ী। তবে কাকেরা উড়তে পারে বলে তাদের রাস্তার গ্রিড নেটওয়ার্ক অনুসরণ করতে হয় না, তারা সবচেয়ে ছোট পথ ধরতে পারে। অবশ্যই, বিশাল আকাশচুম্বী ভবন থাকলে ব্যাপারটা এমন নাও হতে পারে, কিন্তু CEO এই সার্ভিসটি চালু করছেন ম্যানহাটন, ক্যানসাসে (যা "দ্য লিটল অ্যাপল" নামেও পরিচিত), যেখানে কাকেরা সহজেই নিচু ভবনগুলোর ওপর দিয়ে উড়ে যেতে পারে। ম্যানহাটন, ক্যানসাসে এমন সার্ভিসের সম্ভাব্য চাহিদা কত হবে, আর মাথার ওপর দিয়ে এত পাখি উড়ে যাওয়া নিয়ে স্থানীয় পথচারীরা কেমন বোধ করবেন, সেসব অন্য এক দিনের ভাবনা।

as_crow_flies(start, end) ফাংশনটি ইমপ্লিমেন্ট করুন, যেটি start এবং end ছেদবিন্দু নেয়। দুটোর মধ্যেকার কাকের মতো সোজা দূরত্ব রিটার্ন করুন।

as_crow_flies(0+0i, 3+4i)
#> 5

5. কাকের দিকনির্দেশ বের করুন

আপনার CEO কাকদের এমনভাবে প্রশিক্ষণ দিয়েছেন যেন তারা ড্রাইভারদের মতোই ধরনের দিকনির্দেশ অনুসরণ করে। তবে CEO-এর দক্ষিণ গোলার্ধের প্রতি একটা দুর্বলতা আছে, তাই তিনি কাকদের প্রশিক্ষণ দিয়েছেন আপনার প্রজেক্ট ম্যানেজার সিস্টেমের বাকি অংশে যে কম্পাস ব্যবহার করেন, তার থেকে আলাদা একটি কম্পাস দিয়ে। আপনার CEO আসলে বেশ খামখেয়ালি একজন মানুষই বটে। CEO-এর কম্পাসে উত্তর থাকে ঋণাত্মক কাল্পনিক দিকে, আর দক্ষিণ থাকে ধনাত্মক কাল্পনিক দিকে। এটি ড্রাইভারদের উত্তর/দক্ষিণ দিকের ঠিক উল্টো, আর পূর্ব/পশ্চিম দিক অপরিবর্তিত থাকে।

crows_directions(start, end) ফাংশনটি ইমপ্লিমেন্ট করুন, যেটি start এবং end ছেদবিন্দু নেয়। ড্রাইভারের দিকনির্দেশের অনুরূপ জটিল সংখ্যা রিটার্ন করুন, তবে উত্তর/দক্ষিণ উল্টো করে।

driver_directions(0+0i, 7+5i)
#> 7-5i

driver_directions(-2+3i, 4-5i)
#> 6+8i
GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি একটি নতুন উইন্ডো বা ট্যাবে খোলে
R Exercism

কাক ক্যাব শুরু করতে প্রস্তুত?

Exercism-এ সাইন আপ করুন, R ট্র্যাকের 21টি কনসেপ্ট111টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।