মনের দুয়ার খুলে

[অবসরের পর অফিসের পত্রিকার জন্য বাবার লেখা গল্প।]

৩১শে মার্চ ২০১৫। সবে শেষ হয়েছে দীর্ঘ পঁয়ত্রিশ বছর একমাস বারোদিন বিস্তৃত জীবনের এক পর্ব। ফেলে এলাম কর্মজীবন, সামনে রইলো শুধুই অখণ্ড অবসর। দপ্তরে বিদায় সম্ভাষণের পর নিকট সহকর্মীরা চলেছেন পরিবারের কাছে আমাকে পৌঁছে দিতে। দপ্তরকে পিছনে রেখে পথ যতই এগিয়ে চলেছে বাড়ির উদ্দেশ্যে, মন যেন ততই চলতে চাইছে পিছনের দিকে।

সেটাও ছিল মার্চ মাস, তবে সালটা ১৯৮২। সদ্যই দীর্ঘ এগারো মাস ট্রেনিং শেষ করে পেশাগত জীবনে প্রথম ফিল্ড করতে এসেছি রাজস্থানের উদয়পুর জেলার একাংশে। পশ্চিমাঞ্চলের সদর দপ্তর জয়পুর ছেড়েছিলাম আরও চারমাস আগে – অর্থাৎ ডিসেম্বর ১৯৮১। সে সময়ে অনধিক ত্রিশ দিনের মধ্যে এক জায়গার কাজ শেষ করে, তাঁবু গুটিয়ে পরবর্তী জায়গায় আবার তাঁবু লাগিয়ে ভূ-তাত্ত্বিক মানচিত্র আঁকার কাজ এগিয়ে নিয়ে যেতে হতো। এবার তাঁবু লাগিয়েছি ঝুঁন্ত্রি নামে ছোট্ট এক গ্রামের লাগোয়া এক একাকী টিলার উপরে। এ গ্রামেই কুয়ো থেকে মিলবে পানীয় জল, পাশের গ্রামেই আছে সদর দপ্তরের সঙ্গে চিঠিপত্রে যোগাযোগ করবার জন্য গ্রামীণ ডাকঘর আর সপ্তাহের হাটের দিনে শাকসব্জি। টিলার সামনে দিয়েই যে ধূসর পথের রেখা ডাইনে-বাঁয়ে প্রসারিত, তাতে একটি যাত্রীবাস বেশ দূরের মফঃস্বল শহর কোজাভারায় দিনে একবার যাতায়াত করে. কাজেই সবদিক বিবেচনা করে ঝুঁন্ত্রি গ্রামের সেই টিলাই হলো আমার পরবর্তী একমাসের ঠিকানা। ট্রেনিং চলাকালীনই বিয়ে হয়েছিল – সঙ্গে তাই মমতা।

সকালে কাজে বের হওয়ার আগে প্রাতরাশের জন্য আর কাজ শেষে ফিরে প্রায় বিকেল নাগাদ আহারে বসতাম তাঁবুর চিকঘেরা ছোট্ট জায়গায়। টিলার উপরে তখন বইতো শীতল, মনজুড়োনো হাওয়া। অথচ দুপুরে পাথুরে জমি মার্চ মাসের দাবদাহে তৈরী করত অসহ্য গরম, চিকের বাইরে দৃষ্টিতে সবকিছুই লেলিহান গরমে কম্পমান। সকালে বা বিকেলে চিকের বারান্দায় বসলে দৃষ্টি অনেকটাই অবারিত। কেবল সামনে কিছু দূরে আড়াআড়ি ভাবে প্রসারিত আরাবল্লীর নাতি উচ্চ, রুক্ষ এক পাহাড়ের শিরা। সে পাহাড়ের ঢালে আর শিরা বরাবর ছড়ানো ছিটানো ঘর নিয়ে আরও একটা গ্রাম। তুলনায় বড় ঝুঁন্ত্রি তাঁবুর পিছনের দিকে হওয়ায় সাধারণত দৃষ্টির আড়ালে রয়েই যেত। চিকের বারান্দায় বসে বাম দিকে কোনাকুনি তাকালে নজরে আসতো শীর্ণ এক মজা নালা বাস চলবার পথটাকে ভিজিয়ে দিয়ে একদিক থেকে আরেকদিকে বয়ে চলে আর পথেই সবুজ প্রাণের সঞ্চার করে লালন করছে এক সবুজ বক্ররেখা। সেই একমাত্র আশ্রয়ে দিনভর নাচানাচি করত কিছু কাদাখোঁচা পাখি। টিলার উপরে চিকঘেরা বারান্দায় বসে চরাচরের দিকে দৃষ্টি প্রসারিত করে আমরা দুজন যখন নিজেদের এই পটভূমির একমাত্র দ্রষ্টা মনটাকে নিরুদ্দেশে ছুটি দিতাম তখনই হয়তো ঘুঘু পাখির অলস করা ডাক আবার আমাদের সম্বিৎ ফিরিয়ে দিতো। এ ভাবেই মানচিত্র তৈরির কাজের সঙ্গেই মগ্ন রয়েছি রাজস্থানের রুক্ষ প্রকৃতির মাঝেও তার রূপ ও রসকে উপলব্ধি করতে।

এক সন্ধ্যেয় আমাদের কাছে এক বৃদ্ধ ধীর, গাম্ভীর্যপূর্ণ পদক্ষেপে তাঁবুর পিছনের দিক থেকে এলেন। আলাপচারিতায় তিনি আমাদের এ হেন এক অখ্যাত গ্রামে এমনভাবে তাঁবু বাসের উদ্দেশ্য, আমাদের আদত নিবাস, সঙ্গে দৈনিক মজুরিতে কর্মরত ছেলেদের বৃত্তান্ত ইত্যাদি সবই জানলেন। নিজেকে ঝুঁন্ত্রি গ্রামেরই এক বাসিন্দা বলে পরিচয় দিয়ে জানালেন তিনি আমাদের তাঁবু খাটাবার দিন ইস্তক পর্যবেক্ষণ করবার পর কৌতূহল বশতঃ-ই আজ এসেছেন আলাপ করতে। বিদায়ের জন্যে উঠে তিনি জানতে চাইলেন এ গ্রামে আমাদের কোনো রকম অসুবিধা আছে কি না। তাঁবু ফেলবার জন্য সরকারী টিলা, পাশেই জলের কুয়ো, নজরের মধ্যেই ঝুঁন্ত্রি গ্রাম, অনতিদূরে হাট আর ডাকঘর, সারাদিনে একবারের জন্য হলেও মফঃস্বল শহরের সঙ্গে বাসে যোগাযোগ – এর বেশি ভূ-তাত্ত্বিকের আর কী প্রয়োজন? তবুও বৃদ্ধকে জানালাম আমিষাশী হয়েও একনাগাড়ে শুধুই শাকসব্জি খাওয়ার অসুবিধার কথা।  নিরুত্তর বৃদ্ধ যেমন ধীর পায়ে এসেছিলেন তেমনই ধীর পায়ে গ্রামের দিকে ফিরলেন। একটু বাদে সন্ধ্যে নামলে তাঁবুতে লণ্ঠন পৌঁছতে এসে রান্নার ছেলেটা জানালো বৃদ্ধকে গ্রামে সকলে ঠাকুরসাহেব বলে সম্বোধন করে এবং তিনি গ্রামের সকলেরই মাননীয়, শ্রদ্ধেয়।

রবিবার, সাপ্তাহিক ফিল্ডের ছুটি, মমতার সঙ্গে চিকের বারান্দায় সকালে বসে রয়েছি। যথাসময়ে কোজাভারাগামী যাত্রীবাসটা টিলার নীচে এসে থামলো। যাত্রীদের ওঠা-নামা দেখছি। জিনিসপত্র বাসের ছাদে ওঠানো-নামানো চলছে। নজরে এলো একটি মাঝ বয়েসী লোক বেশ দৌড়েই আমাদের তাঁবুর দিকে আসছে। সে অত্যন্ত দ্রুত টিলার ঢাল বরাবর উঠে এসে তাঁবুর চিকের মাটিতে একটা পুঁটুলীতে কিছু একটা নামিয়ে রেখেই যেমন দ্রুত এসেছিল তেমনই আবার বাসের দিকে ফিরে গেলো। বাস রওনা দিল।  আমরা হতবাক বসেই রইলাম। লোকটিকে ভালভাবে নজর করবার ফুরসতও পেলাম না।  রান্নার ছেলেটিকে ডেকে বললাম পুঁটুলীতে কী আছে খুলে দেখতে। ভিতর থেকে বের হলো বেশ কয়েকটা মুরগির ডিম।  কে ওই অচেনা লোক, কেনই বা সে মুরগীর ডিম রেখে গেলো – কিছুই বুঝলাম না।  রান্নার ছেলেটিকে বললাম ডিম আবার আগের মতই পুঁটুলীতে বাঁধতে।

ধন্দ কাটলো সন্ধ্যেয় কোজাভারা ফিরতি বাস ঝুঁন্ত্রি পৌঁছলে। দেখা গেলো লোকটি এবার স্বাভাবিক গতিতে টিলার ঢাল ভেঙে আমাদের কাছে আসছে। লোকটির সঙ্গে কথা বলে জানা গেলো এ গ্রামের ঠাকুর-সাহেব লোক মারফৎ পাশের গ্রামে তাকে খবর পাঠিয়েছিলেন আমাদের জন্য ডিম পাঠাতে। ফের বাস ধরবার তাগিদে সে আমাদের সকালে এ কথা বলবার সুযোগ পায় নি।  মনে পড়ে গেলো কয়েকদিন আগেই ঠাকুরসাহেবকে নাগাড়ে শাকসব্জি খাওয়ার অসুবিধের কথা জানিয়েছিলাম। ঠাকুরসাহেব আর এই লোকটির প্রতি কৃতজ্ঞতায় আমাদের মন ভরে উঠলো। ইতিমধ্যেই বাস ঝুঁন্ত্রি ছেড়ে দেওয়ায় এই অতিথিপরায়ণ লোকটিকে সন্ধ্যের অন্ধকারেই হেঁটে গ্রামে ফিরতে হবে।  সে দিনের প্রাপ্য দাম নিয়ে সে জানালো এবার থেকে সে নিজেই আমাদের ডিমের প্রয়োজনের খবর রাখবে।

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

ভোরবেলা আধো ঘুমে আবারও সেই ঢোলের আওয়াজ। তাঁবুর ছোট্ট জানলার পর্দা ফাঁক করে দেখতে পেলাম বাইরে ছাই রঙা আকাশ। তখনও ভোরের আলো ভালো করে ফোটেনি। এবার ঢোলের আওয়াজ যেন আরো স্পষ্ট হয়ে উঠছে। ক্রমেই যেন সে আওয়াজ আরও কাছে এগিয়ে আসছে। উৎসুক হয়ে বিছানা ছেড়ে তাঁবুর বাইরে বের হয়ে এলাম। অবাক কান্ড। সামনের পাহাড়ের ছোট্ট গ্রামটির ছেলেমেয়েরা ঢোলের সঙ্গে নাচতে নাচতে, গাইতে গাইতে টিলার ঢাল বেয়ে আমার তাঁবুর দিকেই এগিয়ে আসছে। তাড়াতাড়ি মমতাকে ঘুম থেকে ডেকে তুললাম। সেই আধো আলো – আধো অন্ধকার ভোর রাতে দুজনে উপভোগ করলাম নির্মল আনন্দে মাতোয়ারা প্রাণচঞ্চল দেহাতি মানুষদের উচ্ছাসভরা নাচগান। স্থানীয় ভাষায় গানের কথা না বুঝলেও তাদের সম্মিলিত সুর, নাচের তাল, মুক্ত ফোয়ারা বুঝিয়ে দিল বসন্ত আজ এসেছে আমাদের আঙিনায়। চৌকিদারের সঙ্গে আলাপ করে সামান্য কিছু অর্থ ওদের একজনের হাতে দিলাম। ওরা যেমন গাইতে গাইতে, নাচতে নাচতে ঢোল বাজাতে বাজাতে এসেছিল, তেমনই আবার নিজেদের গ্রামের দিকে রওনা দিল।  ততক্ষনে আকাশ ফর্সা হয়ে এসেছে।

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

বিকেলে গিয়ে দেখলাম গ্রামের মধ্যস্থলে ফাঁকা জায়গায় সব গ্রামবাসী একত্রিত হয়েছে। তিনটি মাত্র কাঠের চেয়ার রাখা হয়েছে। একটি ঠাকুর সাহেবের, বাকি দুটি আমাদের দুজনার। উৎসব উপলক্ষ্যে মহিলারা রঙীন ঘাগরা, চেলি, ওড়না আর ভারী ভারী রুপোর গয়নায় সেজেছে। রুক্ষ প্রকৃতির ধূসরতার মাঝে সে সব রঙ আরও রঙীন হয়ে নজর কাড়ছে। বুঝলাম মহিলারা মমতার অনবগুণ্ঠিত মুখ দেখে খুবই বিস্মিত। পুরুষরা পরিষ্কার ধুতি-জামা আর বিশাল রঙীন পাগড়ীতে সজ্জিত। ঠাকুর সাহেবও সযত্নে রঙীন পাগড়ি লাগিয়ে অত্যন্ত গম্ভীর, ধীর পায়ে নিজের চেয়ারটিতে এসে বসলেন। মহিলারা কুণ্ঠাহীন স্বরে, এক সঙ্গে গান গাইতে লাগলেন। তাদের সমবেত গানের সুর ছোট্ট গ্রামের সীমানা ছাড়িয়ে উম্মুক্ত প্রান্তরে মিলিয়ে গেল, গ্রামের সবাই ঠাকুর সাহেবের সঙ্গে আমাদের দুজনকেও প্রণাম করলো। ঘরে পেষা গম আর ঘরেরই তৈরী ঘি-এ বানানো একরকম হাল্কা মিষ্টি, সঙ্গে পাঁপড়ভাজা খাওয়া হলো।

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

তাঁবু গুটিয়ে মালপত্র সব ট্রেনে জয়পুরের উদ্দেশ্যে পাঠিয়ে দিয়ে গাড়িতে জয়পুরের দিকে রওনা দিলাম। সরকারী গাড়ি আমাদের উদয়পুর রেল স্টেশন পর্যন্ত পৌঁছে দেবে। বাকি পথ পাড়ি দেব রেলে। উদয়পুর স্টেশনে যাওয়ার পথে সরকারী গাড়িতে গেলাম জাওয়ারের সেই হাসপাতালে। অনেক জিজ্ঞাসা আর খোঁজের পর হাজির হলাম ঠাকুর সাহেবের বিছানার পাশে। তাঁকে জানালাম আমি ঝুঁন্ত্রি ছেড়ে কলকাতায় নিজের বাড়িতে ফিরে যাচ্ছি বদলীর আদেশ পেয়ে। তিনি অনেক কষ্টে এক হাত তুলে আমাদের দু’জনকে আশীর্বাদ করলেন। ওঁনার চোখেও তখন কৃতজ্ঞতা আর বিচ্ছেদবেদনা।

চিন্তায় ছেদ পড়ল রজকবাবু আমার বাড়ির সামনে গাড়ি রাখতে। অফিসের ব্যাগটা হাতে নিয়ে শেষবারের মতো অফিসের গাড়ি থেকে নামলাম বাড়ির গেটে। সহকর্মীদের হাতে রয়েছে অফিস থেকে পাওয়া পুষ্পস্তবক, মিষ্টির প্যাকেট, স্মারক উপহারের ঘড়িটা।

The Answer

I looked up at the tree. Its branches spread magnificently above me, its canopy catching the glittering late afternoon sun. Its limbs spread outwards from its trunk in twisted tendrils feeling their way in an unseen space. The knots and grooves in its bark were crisp artwork on a careful tapestry.

‘Do you know what you must do?’ the voice entered abruptly.

I tilted my head up and the up-side down face of the man with the hat came into view.

There were folds around the edges of his lips. Was it a smile? I couldn’t tell; he was upside down.

I didn’t feel like answering his question. I did not feel as though I was prepared for it.

‘I don’t think I know the first thing about who I am or what I am going to experience next,’ I said in a slow drawl.

He frowned, I think. ‘Do you think there is happiness to be found?’

I closed my eyes and let my muscles loose upon hearing the familiar phrase. It felt so tiring.

‘I was born naked and shivering into this world. Much of my childhood I have forgotten, and is now but a string of false memories coloured by my present desires. Every day this heart plunges into the cold and dark waters deep, deep inside a well. What do I know about happiness?’

There was silence. I opened my eyes, fearing I had offended him.

He wasn’t there.

I sat up and looked around. He wasn’t anywhere. The evening sun shone into my eyes as I searched for his dark form.

Nowhere.

Across the park, I heard a dog barking. Children frolicking in the water.

I lay back down and stared at the tree again.

Albert Camus said that the only serious philosophical question was that of suicide.

A small cynical voice in my head sniggered as it noted this thought. ‘It’s a tree. How did it make you think of this? You’re going to be hard to fix.’

I let out a long, slow breath. Did I really already know what to do?

In the distance, the tower clock of the university began to ring the hour. In that split moment, there was no room for the voice in my head any more.

As the voice returned and began its dissatisfied search again, I smiled at it.

I already had my answer.

 

Letting Go

The last rays of the sun caressed a soft paint of a sad gold on the brave steel towers of the young city. The dark ink of the quiet night hung watchful on the opposite horizon, stealthily creeping into the space given up by the receding light. The glass and steel vertices of the craggy city center reflected glints of the fading glow through my windows, as I sat contemplating the unbearable despair of being sentenced inside my skull for the rest of my life.

Here it is all, my feverish mind croaked from the corner of the familiar damp prison-cell: look at the pastel gradient of the dusk sky, the brown winter fingers of the tree branches scratched across that easel. Look at that incredible ambitious human habitat in the distance that lunges forth into the vertical. Look at all the being and the happening and the contemplatable beautiful in the observable world. This all I have given you, this all I create for you, this is me, do you not see? What of do you complain then? The very perfection and stillness against which you judge your being to be so ill and incomplete is also born out of and crafted and witnessed by another part of that very same being. What then necessitates this constant comparison and dog-fighting part of your living experience against another? As you give away the prize to one, do you not also create the rejected rest that will moan and claw and keep heaving their pathetic languishing dying breaths in this lightless cave?

Do you not see, that it is not in fact any property of what you call the inhabitable prison of your skull, but your incessant readiness to jump to heartless rejections of the home of your living, that is the root of your psychosis? Let it go, let it all go. It is not an affliction, it is an indulgence. You are clinging to the mythic tree that you complain will not let you free. It is not an act of acquiring more, it is an act of doing and demanding less. It is here, right here, the key is in your palm, why won’t you look? There is room always to step back, opportunities always to keep unclenching that fist from the sand you wish so hard to hold on to.

Lyapunov exponent of the logistic map (Mathematica Code)

In a previous post I’d shown a way to get the Lyapunov exponent from the time series data of any map. In this quick tutorial, I’ll show you a cleaner way to get the Lyapunov exponent for the specific case of the logistic map, and then using a really short script in Mathematica, plot it against r.

First the mathematical analysis that simplifies the expression for the Lyapunov exponent for a map, and particularly the logistic map. This discussion follows this article.

Suppose the initial infinitesimal perturbation is \delta x_{0}. Then we have, for n\rightarrow\infty:

\left|\delta x_{n}\right|=\left|\delta x_{0}\right|e^{\lambda n}\Rightarrow e^{\lambda n}=\underset{\delta x_{0}\rightarrow0}{\lim}\left|\frac{\delta x_{n}}{\delta x_{0}}\right|=\left|\frac{dx_{n}}{dx_{0}}\right|.

But we can write:

\frac{dx_{n}}{dx_{0}}=\frac{dx_{n}}{dx_{n-1}}\frac{dx_{n-1}}{dx_{n-2}}\ldots\frac{dx_{1}}{dx_{0}},

where each x_{i}=f(x_{i-1}). So we have:

\frac{dx_{n}}{dx_{0}}=f'(x_{n-1})f'(x_{n-2})\ldots f'(x_{0}).

Therefore,

\;e^{\lambda n}=\left|f'(x_{n-1})f'(x_{n-2})\ldots f'(x_{0})\right|

\Rightarrow\lambda(r;x_{0})=\underset{n\rightarrow\infty}{\lim}\frac{1}{n}\ln\left|f'(x_{n-1})f'(x_{n-2})\ldots f'(x_{0})\right|

=\underset{n\rightarrow\infty}{\lim}\frac{1}{n}\sum\limits_{k=0}^{n-1}\ln\left|f'(x_{k})\right|.

For the logistic map, f'(x)=r(1-2x).
So we have:

\lambda(r;x_{0})=\underset{n\rightarrow\infty}{\lim}\frac{1}{n}\sum\limits_{k=0}^{n-1}\ln\left|r(1-2x_{k})\right|.

We can put the above formula in a short Mathematica script to obtain \lambda as a function of r and plot it. The following is the code:

\[Lambda][r_] := Module[{f, l},
   f[x_] := r x (1 - x);
   l[x_] := Log[Abs[r (1 - 2 x)]];
   Mean[l[NestList[f, 0.1, 1*^2]]]];
Plot[\[Lambda][r], {r, 0, 4}, PlotStyle -> Thickness[.0001], 
 AxesLabel -> {"r", "\[Lambda](r)"}]

And the following is the output:
Lyapunov exponent for logistic map (Mathematica code)In the line that uses Nestlist, we specify the starting point of the trajectories. However, I noticed that the output does not depend on the starting point.

Training Neural Networks with Genetic Algorithms

In this blog post I present my findings of an independent analytical and computational study of using genetic algorithms to train neural networks. This was my final project for an Introduction to Cognitive Science course that I took at The University of Texas at Austin, under Dr. David Beaver.
My motivation comes from the fact that animal brains, and particularly the human brain which is the topic of this entire course, are themselves genetically evolved neural networks. Therefore, artificial neural networks trained by genetic algorithms are a good starting rudimentary model of understanding the hardware of the brain. This sentiment is echoed in my primary reference, Evolutionary Algorithms for Neural Network Design and Training, Branke et al (1995). However, the paper mostly discusses the idea qualitatively, and I decided that since it is a relatively simple algorithm to implement, I would benefit my understanding to a much greater extent by implementing it myself on some simple networks.

Background

McCulloch-Pitt Neurons

McCulloch-Pitt Neuron

A McCulloch-Pitt neuron is a simple decision-making unit that forms the building block for the kind of artificial neural networks I have constructed and studied. It has a set of inputs (each of which is a 0/1 bit) connected to it via weighted links. It checks if the weighted sum of the inputs exceeds a specified threshold t, and passes an output 1 if it does, and 0 if not.

Artificial neural networks

Neurons of the above kind can be connected and their weights and thresholds set in ways to have their action emulate desired computational operations. This is called an artificial neural network. The following are two simple networks that act as 2-input OR and AND gates:
OR Gate AND Gate
Each network has weights of 1 each. The OR gate has a threshold of 0.5 whereas the AND gate has a threshold of 1.5.
It should already become clear that there isn’t a unique set of weights and thresholds to have a neural network perform a certain task. We shall delve more on this later.

Training artificial neural networks

What if we wish our network to perform a certain kind of operation but we do not know what weights and thresholds will do the work? First, we need to define in a simple way what is meant by a certain operation. It means mapping the set of possible input tuples to their right answers. This is called a truth table. The following is the truth table for a two-input XOR gate for example:
\boldsymbol{i_{1}} \boldsymbol{i_{2}} \boldsymbol{o}
0 0 0
0 1 1
 1 0 1
 1  1 0
A standard way of converging on the right set of weights for a neural network prescribed to perform a certain task is by the use of learning rules. These rules update the weights based on the difference between the correct answer for a set of inputs and the actual answer.

Limitations of learning-rule based weight training

However, this simple method often fails to converge because the number of nodes in the network and the connections between them may be wrong to start with, such that no set of weights between them would provide the desired operation. We can see this when we use the simple connectivity of the OR and AND gates illustrated above and try to emulate a XOR gate and the process does not converge.
Therefore, in a more general case the problem might be extended to include the structure of the network as well, and now the question extends to finding:
  1. The number of nodes in the network.
  2. Their connectivity, i.e. the adjacency matrix (the i,j th element of this is 0 or 1 depending on whether the i th and j th nodes are connected).
  3. The weights of the connections. 2 and 3 may be combined into finding a weighted adjacency matrix, where a zero matrix element implies that two nodes are disconnected, and a non-zero element specifies the weight of the connection.
  4. The thresholds of firing of the neurons.
Some of these variables are discrete and others are continuous, and they are interrelated in a complex way. All of this means that learning rules cannot be simply generalized to find all the variables using an updating scheme. Herein lies the utility of genetic algorithms.

Genetic Algorithms

Genetic algorithms are commonly used where the problem can be formulated as a search in several dimensional parameter space, and a fitness function can be attached to any choice of parameters (a measure that mirrors how close the solution represented by those parameters is to the desired solution). The following schematic illustrates a typical genetic algorithm.
Genetic Algorithm Flowchart
In the context of constructing a neural network, genetic algorithms provide a natural method of solution in the general case where all of the mentioned variables are floating and can be concatenated into a string.

Implementation

There are some important points to note about my particular implementation of the method:
  1. For the sake of simplicity and owing to limited time, the only floating variables were the weights and thresholds, i.e. the number and connectivity of neurons was fixed. It is not hard to imagine extending this implementation to float those parameters as well.
  2. The fitness function is chosen to be the sum of the absolute differences between the correct answers and the answers given by the network. For example, consider the situation when we are trying to model an OR gate and our network gives us the following answers:
\boldsymbol{i_{1}} \boldsymbol{i_{2}} Actual answer Network’s answer
0 0 0 1
0 1 1 0
1 0 1 0
1 1 1 1

Then the fitness of the network is going to be |0-1|+|1-0|+|1-0|+|1-1|=3. By this definition, then, the lower the fitness, the better the network, and a fitness of zero means that the network achieves the desired behaviour for all inputs. As long as the fitness measure ranks the individuals accurately based on their performance, the exact form of the fitness is irrelevant to the working of the algorithm.

  1. The reproduction is sexless, i.e. there is no mating. This means that in each iteration, the fittest individual is selected and a new generation is created by mutating each of its parameters.
  2. To speed up convergence and make it monotonic, if in an iteration all of the offspring are less fit than the parent, the parent is selected again. This ensures there is no retrograde evolution.

Code

The following is the program in R:
xornet<-function(i1,i2,w){
  m1=i1*w[1]+i2*w[3]>w[7]
  m2=i1*w[2]+i2*w[4]>w[8]
  return(m1*w[5]+m2*w[6]>w[9])
}

#calculates the fitness of a network defined by a set of parameters
fitness<-function(w){
  s=0
  for (i1 in c(0,1)){
    for (i2 in c(0,1)){
      s=s+abs(xornet(i1,i2,w)-xor(i1,i2))
    }
  }
  return(s)
}

#initialize random population of weight vectors
pop<-NULL
for (i in 1:10)
  {
  pop<-rbind(pop, rnorm(9))
}
ftraj<-NULL
wspace<-NULL
for (gen in 1:1000){
  #sort according to fitness
  fitnesslist<-NULL
  for (i in 1:dim(pop)[1]){
    fitnesslist<-c(fitnesslist, fitness(pop[i,]))
  }  
  pop<-cbind(pop,fitnesslist)
  pop<-pop[order(pop[,10]),]
  #list the parameter vectors that work. Can be plotted to visualize the solution region in parameter space
  for (i in 1:10){
    if ((pop[,10]==0)[i]){
      wspace<-rbind(wspace,c(pop[i,1],pop[i,2]))
    }
  }
  #list highest fitness against generations
  ftraj<-rbind(ftraj,fitness(pop[1,]))
  
  #generate new generation by mutations from fittest
  fittest=pop[1,]
  pop<-NULL
  for (i in 1:9){
    pop<-cbind(pop, rnorm(10, mean = fittest[i], sd = 1))
  }
  pop<-rbind(fittest[1:9],pop)
}
plot(ftraj, pch=19, xlab="Generation", ylab="Fitness of the fittest")
lines(ftraj)

This code is implementing a neural network for a XOR gate, which corresponds to the highlighted lines. Those are the lines that have to be changed accordingly for other networks.

2-input OR Gate

Analytical observations

OR Gate

In order for the above network to reproduce the truth table of an OR gate, we must have the following:
  1. For (0,0): 0.w_{1}+0.w_{2} \leq t, i.e. t \geq 0.
  2. For (1,0): 1.w_{1}+0.w_{2}>t, i.e. w_{1}>t.
  3. Similarly for (0,1), we have w_{2}>t.
  4. For (1,1): 1.w_{1}+1.w_{2}>t, i.e. w_{1}+w_{2}>t, which is automatically satisfied as long as 2 and 3 are satisfied.
Thus, in the parameter space there is a region of solutions, not a unique set of weights and threshold. These solutions occupy the unbounded region defined by criteria 1, 2 and 3. The surfaces of such regions are called decision boundaries of the perceptrons (neural networks).

In my simplified implementation I further specified the threshold to 1 (as can be seen in the definition of the ornet function in the code), so that the search space of parameters reduces to the 2D w_{1},w_{2} space and the solution region is defined by the area w_{1},w_{2}>1, illustrated below:

OR Gate parameter space

Results

One may consider the evolution of the parameter vector to be a Markov chain. If we plot the fittest of each generation, the Markov chain looks like this for an example run:
OR Gate Markov Chain
Notice how we start outside the solution region and wander into it.
If we plot the fitness of the fittest individual of each generation for the markov chain, it converges to 0. Here is a plot for an example run:
OR Gate fitness

This is a scatter plot of w_{1},w_{2} values after convergence for a sample run:

OR Gate solutions

This is in accordance with the solution region schematically depicted previously.

2-input AND gate

Analytical observations

Following similar arguments as for the OR gate, we can conclude the following about the weights and thresholds if the network is supposed to work as an AND gate instead:
  1. For (0,0): 0.w_{1}+0.w_{2} \leq t,i.e. t \geq 0.
  2. For (1,0): 1.w_{1}+0.w_{2}\leq t, i.e. w_{1}\leq t.
  3. Similarly for (0,1), we have w_{2}\leq t.
  4. For (1,1): 1.w_{1}+1.w_{2}>t, i.e. w_{1}+w_{2}>t, which is no longer automatically satisfied.
For a fixed threshold (say 1), the solutions in the parameter space now occupy a bounded triangular region:
AND gate parameter space

Results

All the results are analogous to the case of the OR gate. The only plot I will show here is the space of solutions for an example run, which is in accordance with the solution region found analytically above:
AND Gate solutions

2-input XOR gate

Analytical observations

In an assignment we saw how a network connectivity like the one I’ve used so far fails to converge to the operation for a XOR gate for any choice of weights. This is unsurprising because the response of a XOR gate is not a linear function of its inputs. This requires the network to be more complex. In particular, here is a network constructed by observation that functions as a XOR gate:
XOR Gate
The intermediate OR gate ensures that at least one of the inputs is on, while the NOT AND gate ensures that both are not on at the same time. The outputs from these pass through a final AND gate that makes sure that both these conditions are met.

Results

As we can see, there is some variability introduced in the weights as well as the thresholds. This is an opportunity to use the power of the genetic algorithm to easily extend the method to include the thresholds as floating parameters as well, which is what I have done with the code. The number of nodes and the connectivity is still fixed.
The parameter space is now 9-dimensional, and the solution region occupies a much tinier fraction of it. Therefore convergence takes longer. Here is a plot of the convergence of fitness for a sample run:
XOR Gate fitness
The Markov chain or the solution parameter vectors cannot themselves be plotted because it is a 9-dimensional space.
The weight and threshold values that resulted from this run have been plugged into the schematic. As we can see, the logic of this network is quite different from the one constructed before by observation, yet it manages to produce the same truth table as a XOR gate. This is because the structure, nature, connectivity and operation of the hidden units of two networks may be different, yet their overall behaviour may be the same.
XOR Gate
The emergence of such alternate solutions allows one to see the problem anew in retrospect. This is indeed the beauty of genetic algorithms. It is an unguided method for obtaining seemingly designed solutions.

Conclusions

As we saw, we can use genetic algorithms to train artificial neural networks to perform desired computations. The advantages of the algorithm over standard learning-rule based updating are several.
  • It is more general, i.e. it can be used to find out the number of nodes, connectivity and firing thresholds as well, and is therefore easily scalable for large and complex networks.
  • It is an entirely unguided method and requires little design and foresight.
  • As a side-effect, it also provides a way to visualize the solution region in the search space by plotting solution vectors starting from different starting conditions.
A disadvantage is that since it is unguided by conscious design, it is often much slower to converge than learning-rule based updating schemes.