Sample Programs for Teaching Programming in Kannada

Yesterday, I was asked to explain Arduino concepts to a group of teachers from rural schools in Karnataka at a workshop.

So, I created a set of slides and a set of illustrative computer programs in Kannada.

I was really keen to hear what the teachers had to say because I had been extremely apprehensive about whether anyone would be able to type software in Kannada (the standard keyboards available in India are ASCII keyboards labelled with Roman letters).

So, at the beginning of the class, I asked the teachers whether they could type Kannada using ASCII keyboards.

They said that they could.  They said that they were used to typing using Nudi or Baraha software (that allows one to type Kannada using a Roman alphabet keyboard).

Since I didn’t have Nudi or Baraha installed, I showed them how Google’s Input Tools worked, and they liked them very much (those with laptops insisted that I install Google Input Tools for them after the lecture).

Apparently, all the teachers could type using a Roman keyboard.  They could also all speak some English.

But their level of comfort with English was low when it came to reading and comprehension.

This group of teachers said they found it much easier to read Kannada than English though they typed Kannada on a Latin keyboard.

And they said that for that reason (ease of reading and comprehension), programming tools in the Kannada language would be useful to them.

Acknowledgements: The workshop yesterday was organized by Workbench Projects.  There had been a similar workshop at ArtScienceBLR on March 29th.  So, anyone wishing to learn to program Arduino boards in Kannada can contact either of these organizations.

You can download and explore the Indian language tools from here http://www.aiaioo.com/arduino_in_local_languages/download and the commands are listed here http://www.aiaioo.com/arduino_in_local_languages/index.php.

Below are screenshots of some of the programs:

  1.  Storing an Integer in Memory and Reading it Back

kannada_program_storing

2.  Adding Two Integers

kannada_program_adding.png

3.  Dividing Two Real Numbers

kannada_program_diving.png

4.  Logical Operations

kannada_program_comparing.png

5.  Conditional Transfer of Control

kannada_program_if.png

6.  Repetition

For Loop

kannada_program_for.png

While Loop

kannada_program_while.png

7.  Electronics

kannada_program_electronics.png

Programming in Hindi and Tamil in addition to Kannada

For children who are taught computer science in Indian languages, conventional software programming can pose a challenge because most programming languages use the Roman alphabet.

We’ve created a way to allow students and teachers to write Arduino programs in Indian languages (at the request of Arduino India).

Arduino boards can now be programmed in Hindi and Tamil in addition to Kannada (as already described in an earlier post).

The Indian language extensions can be downloaded from our website.

These are the words used as replacements for English words: http://www.aiaioo.com/arduino_in_local_languages/

The website allows one to comment on and discuss the keywords picked as replacements for English words.

There’s still a lot of work to be done on the choices.

Very specifically, we’re looking for ways to simplify the words so that school children will find them easier to remember and type.

Any ideas for facilitating the learning process for children would be very welcome.

Illustrative Example

For example, we used to translate analogWrite as “ಅನಂಕೀಯವಾಗಿ_ಬರೆ” in Kannada, (“अनंकीय_लिखो” in Hindi and “அனலாக்_எழுது” in Tamil) using the coined word ‘anankiiya’ (negation of ‘ankiiya’ meaning digital) or the transliteration of ‘analog’.

However, during a discussion, a physicist who helped with the Kannada (thank you, Padmalekha) suggested that we use the phrase “write without spaces” for analogWrite.

And then it hit us that we could just use the phrase “write value” for analogWrite and “write number” for digitalWrite.

The following translations for analogWrite: “ಮೌಲ್ಯವನ್ನು_ಬರೆ“, “मूल्य_लिखो” and “மதிப்பை_எழுது” are much more intuitive.

The new translations for digitalWrite are also just as easy to comprehend: “ಅಂಕೆಯನ್ನು_ಬರೆ“, “अंक_लिखो” and “எண்ணை_எழுது

The process of simplification is an ongoing one, and we hope in a few months’ time to have a generally agreed-upon set of translations, after taking everyone’s inputs into consideration.

Syntax

The Arduino IDE with extensions now supports syntax highlighting in Indian languages. This makes it easier to program in the local language.

This is how Kannada code looks:

Kannada Code

programming_kannada

And here is how it looks in Hindi and in Tamil.

Hindi Code

programming_hindi

Tamil Code

programming_tamil

 

A Naive Bayes classifier that outperforms NLTK’s

We found that by changing the smoothing parameters of a Naive Bayes classifier, we could get far better accuracy numbers for certain tasks.  By changing the Lidstone smoothing parameter from 0.05 to 0.5 or greater, we could go from an accuracy of about 50% to almost 70% on the task of question classification for question answering.

This is not at all surprising because, as described in an earlier post, the smoothing method used in the estimation of probabilities affects Naive Bayes classifiers greatly.

Below, we have provided an implementation of a Naive Bayes classifier which outperforms the Naive Bayes classifier supplied with NLTK 3.o by almost 10% on the task of classifying questions from the questions-train.txt file supplied with the textbook “Taming Text”.

Our Naive Bayes classifier (with a Lidstone smoothing parameter of 0.5) exhibits about 65% accuracy on the task of question classification, whereas the NLTK classifier has an accuracy of about 40% as shown below.

smoothing_graph

Finally, I’d like to say a few words about the import of this work.

Theoretically, by increasing the Lidstone smoothing parameter, we are merely compensating more strongly for absent features; we are negating the absence of a feature more vigorously;  reducing the penalty for the absence of a feature in a specific category.

Because increased smoothing lowers the penalty for feature absence, it could help increase the accuracy when a data-set has many low-volume features that do not contribute to predicting a category, but whose chance presence and absence may be construed in the learning phase to be correlated with a category.

Further investigation is required before we can say whether the aforesaid hypothesis would explain the effect of smoothing on the accuracy of classification in regard to the question classification data-set that we used.

However, this exercise shows that algorithm implementations would do well to leave the choice of Lidstone smoothing parameters to the discretion of the end user of a Naive Bayes classifier.

The source code of our Naive Bayes classifier (using Lidstone smoothing) is provided below:

This implementation of the Naive Bayes classifier was created by Geetanjali Rakshit, an intern at Aiaioo Labs.

 

import numpy as np
import random
import sys, math

class Classifier:
	def __init__(self, featureGenerator):
		self.featureGenerator = featureGenerator
		self._C_SIZE = 0
		self._V_SIZE = 0
		self._classes_list = []
		self._classes_dict = {}
		self._vocab = {}

	def setClasses(self, trainingData):
		for(label, line) in trainingData:
			if label not in self._classes_dict.keys():
				self._classes_dict[label] = len(self._classes_list)
				self._classes_list.append(label)
		self._C_SIZE = len(self._classes_list)
		return
		
	def getClasses(self):
		return self._classes_list

	def setVocab(self, trainingData):
		index = 0;
		for (label, line) in trainingData:
			line = self.featureGenerator.getFeatures(line)
			for item in line:
				if(item not in self._vocab.keys()):
					self._vocab[item] = index
					index += 1
		self._V_SIZE = len(self._vocab)
		return

	def getVocab(self):
		return self._vocab

	def train(self, trainingData):
		pass

	def classify(self, testData, params):
		pass

	def getFeatures(self, data):
		return self.featureGenerator.getFeatures(data)
		

class FeatureGenerator:
	def getFeatures(self, text):
		text = text.lower()
		return text.split()


class NaiveBayesClassifier(Classifier):
	def __init__(self, fg, alpha = 0.05):
		Classifier.__init__(self, fg)
		self.__classParams = []
		self.__params = [[]]
		self.__alpha = alpha

	def getParameters(self):
		return (self.__classParams, self.__params)

	def train(self, trainingData):
		self.setClasses(trainingData)
		self.setVocab(trainingData)
		self.initParameters()

		for (cat, document) in trainingData:
			for feature in self.getFeatures(document):
				self.countFeature(feature, self._classes_dict[cat])

	def countFeature(self, feature, class_index):
		counts = 1
		self._counts_in_class[class_index][self._vocab[feature]] = self._counts_in_class[class_index][self._vocab[feature]] + counts
		self._total_counts[class_index] = self._total_counts[class_index] + counts
		self._norm = self._norm + counts

	def classify(self, testData):
		post_prob = self.getPosteriorProbabilities(testData)
		return self._classes_list[self.getMaxIndex(post_prob)]

	def getPosteriorProbabilities(self, testData):
		post_prob = np.zeros(self._C_SIZE)
		for i in range(0, self._C_SIZE):
			for feature in self.getFeatures(testData):
				post_prob[i] += self.getLogProbability(feature, i)
			post_prob[i] += self.getClassLogProbability(i)
		return post_prob

	def getFeatures(self, testData):
		return self.featureGenerator.getFeatures(testData)

	def initParameters(self):
		self._total_counts = np.zeros(self._C_SIZE)
		self._counts_in_class = np.zeros((self._C_SIZE, self._V_SIZE))
		self._norm = 0.0

	def getLogProbability(self, feature, class_index):
		return math.log(self.smooth(self.getCount(feature, class_index),self._total_counts[class_index]))

	def getCount(self, feature, class_index):
		if feature not in self._vocab.keys():
			return 0
		else:
			return self._counts_in_class[class_index][self._vocab[feature]]

	def smooth(self, numerator, denominator):
		return (numerator + self.__alpha) / (denominator + (self.__alpha * len(self._vocab)))

	def getClassLogProbability(self, class_index):
		return math.log(self._total_counts[class_index]/self._norm)

	def getMaxIndex(self, posteriorProbabilities):
		maxi = 0
		maxProb = posteriorProbabilities[maxi]
		for i in range(0, self._C_SIZE):
			if(posteriorProbabilities[i] >= maxProb):
				maxProb = posteriorProbabilities[i]
				maxi = i
		return maxi


class Dataset:
	def __init__(self, filename):
		fp = open(filename, "r")
		i = 0
		self.__dataset = []
		for line in fp:
			if(line != "\n"):
				line = line.split()
				cat = line[0]
				sent = ""
				for word in range(1, len(line)):
					sent = sent+line[word]+" "
				sent = sent.strip()
				self.__dataset.append([cat, str(sent)])
				i = i+1
		random.shuffle(self.__dataset)	
		self.__D_SIZE = i
		self.__trainSIZE = int(0.6*self.__D_SIZE)
		self.__testSIZE = int(0.3*self.__D_SIZE)
		self.__devSIZE = 1 - (self.__trainSIZE + self.__testSIZE)

	def setTrainSize(self, value):
		self.__trainSIZE = int(value*0.01*self.__D_SIZE)
		return self.__trainSIZE

	def setTestSize(self, value):
		self.__testSIZE = int(value*0.01*self.__D_SIZE)
		return self.__testSIZE

	def setDevelopmentSize(self):
		self.__devSIZE = int(1 - (self.__trainSIZE + self.__testSIZE))
		return self.__devSIZE

	def getDataSize(self):
		return self.__D_SIZE
	
	def getTrainingData(self):
		return self.__dataset[0:self.__trainSIZE]

	def getTestData(self):
		return self.__dataset[self.__trainSIZE:(self.__trainSIZE+self.__testSIZE)]

	def getDevData(self):
		return self.__dataset[0:self.__devSIZE]



#============================================================================================

if __name__ == "__main__":
	
	# This Naive Bayes classifier implementation 10% better accuracy than the NLTK 3.0 Naive Bayes classifier implementation
	# at the task of classifying questions in the question corpus distributed with the book "Taming Text".

	# The "questions-train.txt" file can be found in the source code distributed with the book at https://www.manning.com/books/taming-text.
	
	# To the best of our knowledge, the improvement in accuracy is owed to the smoothing methods described in our blog:
	# https://aiaioo.wordpress.com/2016/01/29/in-a-naive-bayes-classifier-why-bother-with-smoothing-when-we-have-unknown-words-in-the-test-set/
	
	filename = "questions-train.txt"
	
	if len(sys.argv) > 1:
		filename = sys.argv[1]
	
	data = Dataset(filename)
	
	data.setTrainSize(50)
	data.setTestSize(50)
	
	train_set = data.getTrainingData()
	test_set = data.getTestData()
	
	test_data = [test_set[i][1] for i in range(len(test_set))]
	actual_labels = [test_set[i][0] for i in range(len(test_set))]
	
	fg = FeatureGenerator()
	alpha = 0.5 #smoothing parameter
	
	nbClassifier = NaiveBayesClassifier(fg, alpha)
	nbClassifier.train(train_set)
	
	correct = 0;
	total = 0;
	for line in test_data:
		best_label = nbClassifier.classify(line)
		if best_label == actual_labels[total]:
			correct += 1
		total += 1
	
	acc = 1.0*correct/total
	print("Accuracy of this Naive Bayes Classifier: "+str(acc))

 

 

Teaching programming in the Kannada language

An Arduino board is a tiny bare-bones computer.

When Arduino programming is taught in rural India, a problem that is often encountered is that students can only read and write their local language, and the Arduino programming language is English.

(This problem was first described to us by Prakash of Simple Labs in Chennai, a startup that has made it their mission to teach electronics and robotics to children in rural Tamil Nadu using Arduino).

So, we thought we’ve tried to solve the problem, and with help from the Arduino India office, we’ve managed to develop an extension to the Arduino programming environment that allows Arduino boards to be programmed in Kannada.

Here is a screenshot of a program to make an LED attached to Arduino pin number 13 blink on and off every couple of seconds.

programming_kannada

To do this, we had to translate various commands and functions into Kannada.

For example, we translated the return value of the function “void” as “ಖಾಲಿ” (pronounced ‘khaali’).  The word “ಖಾಲಿ” is short, in common use and unambiguous, so we chose it over “ಶೂನ್ಯ” (‘shoonya’) which could also mean zero.

The most difficult translation for the South Indian languages turns out to be the two words in English that are at the core of all programming and logic – the words ‘if‘ and ‘else‘.

There is no word for ‘if’ or ‘else’ in Kannada or Tamil.

For the moment, we’ve approximately translated ‘if’ and ‘else’ as “ಆದರೆ” and “ತಪ್ಪಿದರೆ” in Kannada.

Acknowledgement:  Many thanks to Padmalekha Kydala Ganesha for helping us translate mathematics and physics terms used in Arduino into Kannada (in particular ‘analog’ and ‘to the power of’).

In a Naive Bayes classifier, why bother with smoothing when we have unknown words in the test set?

I came across this question on Stack Overflow a few days ago, and found it very interesting, so I thought I’d post the answer to the question here on the blog as well.

Why do we bother with smoothing at all in a Naive Bayes classifier (when we can throw away the unknown features instead).

The answer to the question is: words are often unknown in some but not all classes.

Say there are two classes M and N with features A, B and C, as follows:

M: A=3, B=1, C=0

(In the class M, A appears 3 times and B only once)

N: A=0, B=1, C=3

(In the class N, C appears 3 times and B only once)

Let’s see what happens when we throw away features that appear zero times.

A) Throw Away Features That Appear Zero Times In Any Class

If we throw away features A and C because they appear zero times in any of the classes, then we are only left with feature B to classify documents with.

And losing that information is a bad thing as we will see below!

Say we’re presented with a test document as follows:

B=1, C=3

(It contains B once and C three times)

Since we’ve discarded the features A and C, we won’t be able to tell whether the above document belongs to class M or class N.

So, losing any feature information is a bad thing!

B) Throw Away Features That Appear Zero Times In All Classes

Is it possible to get around this problem by discarding only those features that appear zero times in all of the classes?

No, because that would create its own problems!

The following test document illustrates what would happen if we did that:

A=3, B=1, C=1

The probability of M and N would both become zero (because we did not throw away the zero probability of A in class N and the zero probability of C in class M).

C) Don’t Throw Anything Away – Use Smoothing Instead

Smoothing allows us to classify both the above documents correctly because:

  1. We do not lose count information in classes where such information is available and
  2. We do not have to contend with zero counts.

Naive Bayes Classifiers In Practice

The Naive Bayes classifier in NLTK throws away features that have zero counts in all of the classes.

This makes it perform poorly when trained using a hard EM procedure (where the classifier is bootstrapped up from very little training data) on data sets with a high occurrence of unknown words (like Twitter feeds).

Here is the relevant code from NLTK 3.0:

def prob_classify(self, featureset):
  # Discard any feature names that we've never seen before.
  # Otherwise, we'll just assign a probability of 0 to
  # everything.
  featureset = featureset.copy()
  for fname in list(featureset.keys()):
    for label in self._labels:
    if (label, fname) in self._feature_probdist:
      break
    else:
      #print 'Ignoring unseen feature %s' % fname
      del featureset[fname]

Related Blog Posts:

  1. Analysing documents for non-obvious differences

  2. Naive Bayes Classifier in OpenNLP

 

Cooking Robot for Indian Cuisine using a Sensor Network Architecture

We had designed a cooking robot not very long ago.  The design was prepared as a creative exercise and there are some kinks in it that need to be ironed out.  We will list the kinks at the end.

The robot essentially uses a sensor network to perform transfer and heat operations.  It can also dip and activate various tools – mixing tools, stirring tools, grinding tools, etc.

Another cool feature of the design is that all tools and operations are driven by a single immovable motor drive.

The cooking robot, if it is realized, should be able to prepare many types of Indian side dishes and cook rice.

One of the things that this robot can’t do is prepare rotis (but there is now an automatic roti maker available in the market that can do that).

In the blog post below, we describe the design of the robot and hereby put it in the public domain.

At the core of the design is the vessel.  This is the only part of the design (apart from various tools) which comes into contact with the food.

cooking_robot_1

The vessel has a handle that allows it to be easily ‘picked up’ by the robot, moved around, turned and released.

Various tools, for example, mixing tools, stirring tools, and beating tools can be fitted with similar handles (but with a drive shaft running within to provide a mechanical driving force to the tool tip).

The robot connects with the vessel through a vessel carrier.  The vessel carrier is just a square piece.  The diagram below shows the vessel carrier in three positions – open, locked and rotated through 45%.

cooking_robot_2

The purple shading denotes the handle of the vessel.  There are two concentric rings with slits (shown in grey) in the rectangular carrier.

When the carrier is open, the slits in the slit rings line up and the vessel handle can slide into the carrier.

When the carrier locks, the inner slit ring rotates around the handle shaft, so it cannot slide out of place.

The slits are now at 90 degrees to each other.  Whenever they are at 90 degrees with respect to each other, the handle cannot slide out.

If both rings rotate, the vessel rotates with them, as shown in the last of the three figures in the above diagram.

Any number of such vessel carriers can be allowed to run along a set of vertical and horizontal tracks as shown in the following figure.

cooking_robot_3

The tracks are called ‘vessel guides’ because the vessel holders can only run along these guides.

The track and the surface they are cut into form the front face of the cooking robot.

So, in this design, the robot operates entirely in 2 dimensions, in a vertical plane parallel to a kitchen wall.  This plane of operation was deliberately chosen to conserve kitchen room, and to allow for pouring operations.

To pour a fluid or mixture from one vessel to another, all that one has to do is position one vessel in a vertical track (N-S) above another vessel running in a horizontal track (E-W) and turn the higher vessel (the pouring vessel).  The pouring vessel rises to keep its lower edge at a steady height.  The receiving vessel adjusts its position horizontally to keep the lower edge of the pouring edge in line with its own center.

At the base of the front face are burners.  They can turn on to provide heating energy and a vessel can position itself at any height above these burners to heat or warm food.

For mixing operations, a vessel holder equipped with a mixing tool would position itself over the vessel whose contents need to be mixed, and the rotating shaft in the handle would be engaged to provide power to the mixing tool’s tip.

The basic ingredients (already washed, cut and ground) were meant to be stored in containers just above the front face so that the ingredients could be transferred to the vessels positioned below them in controlled quantities by suitable methods under the force of gravity.

Power Train

We also designed a power train for the system so that the entire robot would operate using just one base-mounted motor.

At the heart of the power train is a set of vertical and horizontal lifts that run along rails and are propelled by screws (drive bars).

The figure below shows the arrangement of vertical rails (black lines) and drive bars (red lines).

cooking_robot_4

Below is an illustration of the horizontal lifts (rails and drive shafts).

cooking_robot_5

These rails and screws drive lift boxes as shown below.

The lift boxes would run along only one set of rails and the lift boxes running along vertical rails would not interfere with lift boxes running along horizontal rails, as shown below.

cooking_robot_6

In this diagram, the lift boxes (drawn as dotted rectangles) are shown latching on to the vessel carriers using holding bolts.

The holding bolts can be withdrawn and relocked at will, allowing the vessel carriers to be transferred from one lift to another at points of intersection, and to allow horizontal lifts’ holding bolts to avoid colliding with vertical drive shafts.

Below is a rough schematic of the lift boxes.

cooking_robot_7

The holding bolts are shown in blue.

The grippers (shown in solid black) hold on to the guide rails to stop the lift or onto the drive shaft(s) to propel the lift up or down.

We originally meant the system to have two counter-rotating drive shafts to allow the lift box to change direction very rapidly or stop against the drive rail.

The yellow square represents the gear wheels that power the  tools (for mixing, stirring, etc).

The blue square are the holding bolts and they latch onto the vessel carriers through matching slots as shown below.

cooking_robot_8

We had designed a gearing mechanism to lock and unlock vessel handles using cams that transferred power from the drive shafts and gears to power the tools, but those detailed diagrams have been lost.

Feasibility

An industrial robotics startup in Bangalore who evaluated this design for feasibility pointed out some problems in the design:

  1. The vertical plane of operation of the robot. They pointed out that lifting heavy vessels was going to require a lot of power, and would run into other problems like friction, and that it is always much easier to operate in the horizontal plane.  They asked us to study food processor designs and come up with ways to transfer Indian food ingredients between vessels in the horizontal plane.
  2. Friction in many of the components could prove difficult to overcome, for instance in the vessel holder. The weight of the vessel and its ingredients might end up locking the split ring system and preventing it from turning, or it might end up jamming the holding shafts connecting the vessel holder and the lift.

So, it appears that a number of mechanical problems need to be solved before such a product could become a reality.

Temperature Controlled Clothing for South Indian Summers

One of the first things we invented at Aiaioo Labs was a cheap vest that could keep people cool in the hot Bangalore summers.

We had applied for a patent for the vest, but later abandoned the application (it had appeared in the Indian patent office gazette as 2058/CHE/2008, with a filing date of 25.08.2008).

Since we do not intend to pursue the technology to production ourselves, I thought I’d describe it in our blog in the hope that someone interested in the idea might find a way to solve the remaining problems on the road to productising it.

clothing_temperature_controlled_1

This figure illustrates the components of the vest:

  1. Tubing filled with water
  2. A connector that connects the tubing to a reservoir (a bottle) of cold water
  3. A reservoir full of ice-cold water
  4. A hand-pump for circulating the water

clothing_temperature_controlled_5

The tubing is laid out in the pattern shown in the figure above so that cold water, entering at the top, can flow through the tube freely all the way to the bottom, mixing with the fluid already in the tubing.

This prevents the formation of cold spots and permits the water to maintain an evenly cool temperature throughout the vest.

clothing_temperature_controlled_4

The tubes that run up from the reservoir to the top of the vest carry very cold water and the wearer needs to be insulated from them as shown in the above figure.

clothing_temperature_controlled_2

The coolant is circulated using a hand pump – a kind of bellows – as shown above.  There are two reservoirs in the figure, but one reservoir will suffice.

clothing_temperature_controlled_7

The second reservoir comes in handy if the mixing of warm and cool fluids in the tubing does not warm of the coolant to a comfortable temperature.  The second reservoir can then be kept at a higher temperature than the first.

clothing_temperature_controlled_3

The above figure is of a simple pump that I built from commonly available parts – a rubber bulb, two valves and two nozzles.

Field Trials

We built a working prototype of the vest, and on a fine day in 2008, I wore it under my clothes while travelling by bus from Banashankari to Vidyaranyapura.

I thought it felt cooler with the vest on, but not significantly.

Work Remaining

To productise this, among other things, one needs to improve the tubing.

The only tubing whose walls could maintain their shape tended to have thick rubber/plastic insulating walls which impeded the cooling effect of the vest.

Thinner tubes tended to collapse and fold sharply, stopping the circulation of the fluid.

Another issue was the pumping pressure.  The hand pump (the bladder) was sufficient but needed frequent tight short squeezes to pump the fluid through the tube, which became exhausting and monotonous.

If a non-insulating, non-collapsing tubing system could be constructed, and the pump operated by a light battery-powered peristaltic pump, and the cost of the latter kept to within a few hundred rupees, then the vest could become a commercially feasible proposition.