<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4318944459823143473</id><updated>2012-02-14T08:21:48.561+01:00</updated><category term='c#'/><category term='computer science'/><category term='essay'/><category term='css'/><category term='javascript'/><category term='data structures'/><category term='genetic algorithm'/><category term='sql'/><category term='logic'/><category term='php'/><category term='proofs'/><category term='photoshop'/><category term='maths'/><category term='tutorial'/><category term='xna'/><category term='philosophy'/><category term='algorithms'/><category term='game'/><category term='trie'/><category term='library'/><category term='databases'/><title type='text'>Geeky is Awesome</title><subtitle type='html'>A historical record of the geekiness of a drifter in a world where geekiness and awesomeness are disjoint.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-3730774034163280742</id><published>2012-02-12T10:21:00.000+01:00</published><updated>2012-02-13T11:22:48.660+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maths'/><title type='text'>Why multiplying a fraction by 100 gives the percentage of the fraction</title><content type='html'>I remember I had this curiosity about why it is that when you multiply a fraction by a number you get that fraction of that number. Why is it that 1/2 × 5 gives half of 5? Why is it that you find the percentage from a fraction by multiplying that fraction by 100? Why is it that multiplication should have this property?&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Percentages&lt;/h1&gt;As you should know, if for example you have a 10% income tax, that means that out of every 100 units of income you make, 10 units of them are taxes. So a percentage means the number of units you need to take out of every 100 units of a total. This is why it's called "percent", that is, "per hundred", because you are finding the amount of units you need to take our of every hundred units in the total.&lt;br /&gt;&lt;br /&gt;However we can also express this statement using fractions instead of percentages. We can just say that 1/10 of your income is taxes. In fact we can convert fractions into percentages by multiplying the fraction by 100, 1/10 × 100 = 10, that is 10%.&lt;br /&gt;&lt;br /&gt;The reason why we convert fractions to percentages by multiplying the fraction by 100 is the following:&lt;br /&gt;Given a fraction a/b, when we convert it to a percentage, we are changing the denominator of said fraction to 100, leaving the fraction equal to a/b, and taking the numerator. So a/b becomes p/100 and p is the percentage.&lt;br /&gt;&lt;br /&gt;We are finding a number which when divided by 100 gives the original fraction and therefore the amount of units you need to take from every 100 units of a total such that when you divide the amount you took by the total, you get the original fraction. &lt;br /&gt;&lt;br /&gt;&lt;div style="border-style:solid;"&gt;If you think about it, the fraction a/b means two things:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;b is the number of equal sized parts to divide the total and a is the number of such parts to take.&lt;/li&gt;&lt;li&gt;a is the number of units to take out of every b units from the total.&lt;/li&gt;&lt;/ol&gt;For example, if we want to take 3/4 of 20,&lt;br /&gt;&lt;br /&gt;We can either break 20 into 4 equal parts and take 3 of them:&lt;br /&gt;20 = 5 + 5 + 5 + 5 (4 equal parts)&lt;br /&gt;take 3 of the parts and we have&lt;br /&gt;5 + 5 + 5 = 15&lt;br /&gt;&lt;br /&gt;Or we can take 3 from every 4 in 20:&lt;br /&gt;20 = 4 + 4 + 4 + 4 + 4&lt;br /&gt;take 3 from every 4 and we have&lt;br /&gt;3 + 3 + 3 + 3 + 3 = 15&lt;br /&gt;&lt;br /&gt;In general, if we want to take a/b of T,&lt;br /&gt;T = T/b + T/b + T/b ... (for b times) (b equal parts, that is, T/b × b which is equal to T)&lt;br /&gt;take a of the parts and we have&lt;br /&gt;T/b + T/b ... (for a times) = T/b × a&lt;br /&gt;&lt;br /&gt;Or we can take a from every b in T,&lt;br /&gt;T = b + b + b ... (for T/b times) (that is, b × T/b which is equal to T)&lt;br /&gt;take a from every b and we have&lt;br /&gt;a + a + a ... (for T/b times) = a × T/b&lt;br /&gt;&lt;br /&gt;So as long as you accept that T/b × a = a × T/b, you must accept that the two statements are equal.&lt;br /&gt;&lt;br /&gt;If you add to the mix that T/b × a, a × T/b and T × a/b are all equal to (T × a)/b, then you also know that T/b × a = a × T/b = T × a/b. So both statements are also equal to T × a/b which is what we're trying to prove in the first place.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;For example, if you have a total of 50 units and you want to take 1/10 of the total, the number of units you must take from the total, when divided by 50 must result in 1/10. Likewise, if we change the denominator of the fraction to 100, that is, 10/100, then we say that 10% of 50 units is the number of units we must take such that when it is divided by 50 we get 10/100 (which is equal to 1/10).&lt;br /&gt;&lt;br /&gt;&lt;div style="border-style:solid;"&gt;Percentages are useful because we would be standardizing the denominator of fractions in order to make them easy to compare. If we wanted to compare 2/4 to 4/16 we can change the denominators of both fractions to 100 (50/100 and 25/100 respectively) and then we will only have to compare the numerators in order to know by how much one fraction is bigger than the other.&lt;/div&gt;&lt;br /&gt;So what we're doing is finding another fraction which is of the form p/100. However, p/100 must equal a/b in order to remain the same fraction.&lt;br /&gt;&lt;br /&gt;So we have the equation a/b = p/100&lt;br /&gt;We want to find p, so p = a/b × 100 (multiplied both sides by 100)&lt;br /&gt;&lt;br /&gt;So if we want to express 2/4 as a percentage,&lt;br /&gt;2/4 = p/100&lt;br /&gt;p = 2/4 × 100&lt;br /&gt;p = 50&lt;br /&gt;So 2/4 = 50/100 or 50%.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-style:solid;"&gt;I think that the percentage sign "%" can be treated as a symbol representing the constant "1/100". Which means that 50% = 50 × 1/100. This makes sense as in order to go from percentage to fraction form you just change the % back to 1/100 and calculate the expression. 50% = 50 × 1/100 = 1/2.&lt;/div&gt;&lt;br /&gt;And this is why percentages work this way.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;In general&lt;/h1&gt;Now we can generalize this to numbers other than 100. If we use "c" instead of "100",&lt;br /&gt;a/b = p/c&lt;br /&gt;p = a/b × c&lt;br /&gt;&lt;br /&gt;By changing the denominator to c, the numerator p will be the amount of units you need to take out of every c units of a total, such that when you divide the amount you took by the total, you get a/b. But usually we multiply a number by a fraction just to find that fraction of that number. So more simply, p is the number which when divided by c, gives a/b.&lt;br /&gt;&lt;br /&gt;So 1/2 × 5 gives us the number which when divided by 5, gives us 1/2. Hence the answer, 2.5, is half of 5 because when it is divided by 5, the result will be 1/2, or, when 2.5 is multiplied by 2 the result will be 5 (by definition, when you double half of 5 you must get 5 again).&lt;br /&gt;&lt;br /&gt;So really all we're doing is simple subject of the formula.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-3730774034163280742?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/3730774034163280742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2012/02/why-multiplying-fraction-by-100-gives.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/3730774034163280742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/3730774034163280742'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2012/02/why-multiplying-fraction-by-100-gives.html' title='Why multiplying a fraction by 100 gives the percentage of the fraction'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-6367025678748910201</id><published>2011-11-07T10:03:00.000+01:00</published><updated>2012-02-07T19:27:54.693+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='proofs'/><category scheme='http://www.blogger.com/atom/ns#' term='maths'/><title type='text'>A more complete proof that the square root of 2 is irrational.</title><content type='html'>I don't know about you but I never quite liked the &lt;a href="http://en.wikipedia.org/wiki/Square_root_of_2#Proof_by_infinite_descent"&gt;usual proof&lt;/a&gt; by contradiction that the square root of 2 is irrational. It seems incomplete in some way. I never felt convinced by it. Here's what I feel is the missing piece of the puzzle.&lt;br /&gt;&lt;br /&gt;Assume that the square root of 2 is rational. So,&lt;br /&gt;√2 = a/b&lt;br /&gt;=&amp;gt;&lt;br /&gt;2 = (a/b)^2&lt;br /&gt;=&amp;gt;&lt;br /&gt;2 = a^2 / b^2&lt;br /&gt;=&amp;gt;&lt;br /&gt;2 b^2 = a^2&lt;br /&gt;&lt;br /&gt;So far so good. The usual proof continues with the following statement:&lt;br /&gt;&lt;br /&gt;Since a^2 is equal to a natural number multiplied by 2, a^2 is an even number. But for a^2 to be even, a must be even too (see proof in the appendix at the end). So that means that there is a natural number k where a = 2k.&lt;br /&gt;&lt;br /&gt;Since a = 2k and 2 b^2 = a^2,&lt;br /&gt;2 b^2 = a^2&lt;br /&gt;=&amp;gt;&lt;br /&gt;2 b^2 = (2k)^2&lt;br /&gt;=&amp;gt;&lt;br /&gt;2 b^2 = 4 k^2&lt;br /&gt;=&amp;gt;&lt;br /&gt;b^2 = 2 k^2&lt;br /&gt;&lt;br /&gt;Just like for a, b must also be an even number.&lt;br /&gt;&lt;br /&gt;The proof usually ends right there, claiming that since a and b are both even numbers, then the fraction a/b is not simplified and irreducible, contradicting that a/b exists. But let's see where the proof takes us if we just keep on going.&lt;br /&gt;&lt;br /&gt;If both a and b are even, then the fraction a/b can be simplified by dividing both a and b by 2, that is, if a = 2k and b = 2l, then we can say that √2 = k/l. But after doing this we can reapply the same reasoning on k and l and we'll discover that k and l are also both even numbers, and we can do it again and again ad infinitum.&lt;br /&gt;&lt;br /&gt;So, which natural numbers can be divided by 2 infinitely? Only 1 number can do that, zero. But replacing zero for both a and b will not make their quotient a real number, or if you want to define 0/0, it will not result in a number whose square equals 2. So there is no fraction a/b which gives √2.&lt;br /&gt;&lt;br /&gt;So there you have it, a proof that goes on till the end.&lt;br /&gt;&lt;br /&gt;===========================&lt;br /&gt;APPENDIX&lt;br /&gt;Now on to the proof that an even square can only come from an even number squared:&lt;br /&gt;&lt;br /&gt;Let a^2 be an even number.&lt;br /&gt;&lt;br /&gt;a can either be even or odd, that is there must exist an n where&lt;br /&gt;a = 2n or a = 2n + 1&lt;br /&gt;If a = 2n, a^2 = (2n)^2 = 4 n^2 = 2(2 n^2), which is an even number&lt;br /&gt;If a = 2n + 1, a^2 = (2n + 1)^2 = 4 n^2 + 4n + 1 = 2(2 n^2 + 2n) + 1, which is an odd number&lt;br /&gt;&lt;br /&gt;So an even number squared will give an even number and an odd number squares will give an odd number. Hence, a square even number can only come from an even number squared.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-6367025678748910201?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/6367025678748910201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/11/more-complete-proof-that-square-root-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/6367025678748910201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/6367025678748910201'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/11/more-complete-proof-that-square-root-of.html' title='A more complete proof that the square root of 2 is irrational.'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-4071077661833612164</id><published>2011-11-02T14:42:00.001+01:00</published><updated>2012-02-07T19:26:58.504+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Wisdom hierarchy vs Bloom's taxonomy</title><content type='html'>So lately I've been reading about two subjects that I noticed are very related, the Wisdom hierarchy ( &lt;a href="http://www.systems-thinking.org/dikw/dikw.htm"&gt;http://www.systems-thinking.org/dikw/dikw.htm&lt;/a&gt;) and Bloom's taxonomy (&lt;a href="http://www.odu.edu/educ/roverbau/Bloom/blooms_taxonomy.htm"&gt;http://www.odu.edu/educ/roverbau/Bloom/blooms_taxonomy.htm&lt;/a&gt;). First I need to explain each.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Wisdom hierarchy&lt;/h1&gt;This is a hierarchy of how wisdom is obtained and describes the relationship between data, information, knowledge, understanding and finally wisdom.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Data&lt;/h2&gt;Data is symbols and signals which can be observed and analysed, but perhaps not be processed and organized.&lt;br /&gt;An example of this is seeing the symbols "3", "×", "4", "=" and "12". Those symbols may not mean anything to you if you don't know arithmetic.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Information&lt;/h2&gt;Information is data which is given meaning and use. It answers "what", "where", "who" and "when" questions, that is, simple shallow questions. It is when relationships are formed between the different data and context is given to the data. The data has meaning but perhaps it cannot be used.&lt;br /&gt;So now "3×4=12" has a meaning. It means that if you multiply the numbers 3 and 4, the result is equal to 12. You may know what the symbols mean but you may not be in a form that is useful.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Knowledge&lt;/h2&gt;Knowledge is a mass of information which is organized in a way to be useful. It answers "how" questions, that is how can I use the information. The information may be useful but perhaps you don't understand why it is related and how to generate new information from it.&lt;br /&gt;So now we have organized every multiplication of two numbers we learned into a multiplication table. If we want to know what a particular multiplication equals, we know how to do that, we simply look it up our multiplication table. You may know how to multiply numbers together but you may not know why when numbers are multiplied they give a particular number as a result.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Understanding&lt;/h2&gt;Understanding is when you understand the knowledge, when you find a pattern to the organization and can use the pattern to generate new information. It answers "why" questions, that is, why is the information organized as it is in the knowledge. The knowledge may be understood but perhaps it cannot be judged and compared with other knowledge.&lt;br /&gt;So now we understand that multiplication is repeated addition. Now we can add to our knowledge new information which is generated from our understanding rather than from the external world (such as having to ask someone). You may understand how to do multiplication but you may not be able to compare different methods to doing multiplication.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Wisdom&lt;/h2&gt;Wisdom is when you can pass judgement and make decisions to determine what is the best method to use. The question it could answer is "which" questions, that is, which is best.&lt;br /&gt;We now can decide which method we should use to multiply two numbers, be it by looking up the multiplication table, by repeated addition or by long multiplication.&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Bloom's taxonomy&lt;/h1&gt;This is a way of categorizing exam questions in a&amp;nbsp;hierarchy&amp;nbsp;such that as you go up the pyramid, the higher the level of thought required to answer the question.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Remembering&lt;/h2&gt;Remembering type questions are those that only require the student to remember things, without expecting any understanding.&lt;br /&gt;An example question would be "What does the symbol × represent?".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Understanding&lt;/h2&gt;Understanding type questions are those that require the student to know what the things they know actually mean.&lt;br /&gt;An example question would be "Explain what the expression 2×3=6 means in your own words.".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Applying&lt;/h2&gt;Applying type questions are those that require the student to be able to use what they know in a situation.&lt;br /&gt;An example question would be "How many apples would you have if you had 2 baskets with 3 apples in each?".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Analyzing&lt;/h2&gt;Analyzing type questions are those that require the student to break down a problem into parts and see how they are related to each other.&lt;br /&gt;An example question would be "What is the next number in the sequence 21, 42, 63, __".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Evaluating&lt;/h2&gt;Evaluating type questions are those that require the student to justify a decision.&lt;br /&gt;An example question would be "Which multiplication method would you use to multiply 128 by 64 and why?".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Creating&lt;/h2&gt;Creating type questions are those that require the student to create something new to the student.&lt;br /&gt;An example question would be "If all you have is the product of the sum and difference of two numbers and one of the numbers, how can you find the other number?".&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Together&lt;/h1&gt;It is clear that there is a relationship between the two hierarchies. We could say that:&lt;br /&gt;Remembering type questions test the student having memorized data.&lt;br /&gt;Understanding type questions test if the student has derived information from data.&lt;br /&gt;Applying type questions test if the student has developed a useful knowledge from the information and if the knowledge can be readily used.&lt;br /&gt;Analysis type questions test if the student has understood the basis of their knowledge and can derive new information from it.&lt;br /&gt;Evaluating type questions test if the student has obtained any wisdom on the subject and hence can make sound judgement about it.&lt;br /&gt;&lt;br /&gt;The last question type, creating, is not covered by the Wisdom hierarchy and perhaps it predicts yet another higher level form of cognition, perhaps called "creativity", which is when you use knowledge, understanding and wisdom together to derive new knowledge, understanding and wisdom, where knowledge provides the raw material to act on, understanding provides the ways to rearrange the knowledge and wisdom guides you into choosing a solution path which is most likely to give good results. Once this is done you will have learned from experience and would have added new knowledge, a deeper understanding of that knowledge together with new ways of using it and you would be able to make better judgement in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-4071077661833612164?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/4071077661833612164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/11/wisdom-hierarchy-vs-blooms-taxonomy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/4071077661833612164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/4071077661833612164'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/11/wisdom-hierarchy-vs-blooms-taxonomy.html' title='Wisdom hierarchy vs Bloom&apos;s taxonomy'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-5794107462548632593</id><published>2011-09-19T01:07:00.002+02:00</published><updated>2011-09-23T14:21:14.477+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>A lousy tutorial to C# drag and drop</title><content type='html'>Drag and drop is a neat way to allow the user the "transfer" data into a winform control. Here's how to enable drag and drop in a windows form in C#:&lt;p&gt;1. Create your source and target controls. In this case we're using 2 ListViews where the one on the right (called listView1) is the source of the drag and the one on the left (called listView2) is target of the drop. However note that the source of the drag can even be from the windows explorer by drag dropping a file into the control.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-27jr8bL3FHc/TnZ41-YaJLI/AAAAAAAAADQ/czEG75lL0Bw/s1600/1.png" imageanchor="1" style=""&gt;&lt;img border="0" height="347" width="361" src="http://2.bp.blogspot.com/-27jr8bL3FHc/TnZ41-YaJLI/AAAAAAAAADQ/czEG75lL0Bw/s400/1.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;2. Set the AllowDrop property of the control which will receive the drop to true.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-jS3KjFsLNaQ/TnZ46uYaikI/AAAAAAAAADY/EBdkon5bNoY/s1600/2.png" imageanchor="1" style=""&gt;&lt;img border="0" height="244" width="400" src="http://1.bp.blogspot.com/-jS3KjFsLNaQ/TnZ46uYaikI/AAAAAAAAADY/EBdkon5bNoY/s400/2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;3. Set up an event in the control which will be dragged from, that senses that a drag has been initiated, such as the ItemDrag event or the DragLeave event and call the DoDragDrop method. The DoDragDrop method is to be passed the data to be transferred (the object you want the receiving control to get).&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-dM0odQHjTvg/TnZ5CjIPjYI/AAAAAAAAADg/-qMphSMvskE/s1600/3.png" imageanchor="1" style=""&gt;&lt;img border="0" height="126" width="400" src="http://2.bp.blogspot.com/-dM0odQHjTvg/TnZ5CjIPjYI/AAAAAAAAADg/-qMphSMvskE/s400/3.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;4. Set up the DragOver event in the control which will be dropped on, to check if the data being dragged over can be accepted and change the cursor to an invalid cursor picture if not. You can check the type of the data being dragged by using the GetDataPresent method.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-X19Sw8ItDt8/TnZ5HM67ujI/AAAAAAAAADo/2f82M4mzDF8/s1600/4.png" imageanchor="1" style=""&gt;&lt;img border="0" height="160" width="400" src="http://4.bp.blogspot.com/-X19Sw8ItDt8/TnZ5HM67ujI/AAAAAAAAADo/2f82M4mzDF8/s400/4.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;5. Set up the DragDrop event in the control which will be dropped on, to actually do something with the data once it has been dropped. This event will only fire if the DragOver event did not set Effect to None.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-IPO3jGeIOsI/TnZ5MaRPXUI/AAAAAAAAADw/w7qFGPrV_rU/s1600/5.png" imageanchor="1" style=""&gt;&lt;img border="0" height="79" width="400" src="http://1.bp.blogspot.com/-IPO3jGeIOsI/TnZ5MaRPXUI/AAAAAAAAADw/w7qFGPrV_rU/s400/5.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;And there you have it. A lousy tutorial. However, here's something worth mentioning:&lt;/p&gt;&lt;p&gt;If you are transferring an object which could be one of several types and you want to view the object as its base type, then this will not work, as the GetData method will just return null if you pass it a base class for a type. The only was I found to get around this was by created a proxy object which will contain the object of interest casted as its base class, and then what you receive the proxy object in the receiving control you just get the object of interest from it. Like so:&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ZmDywAz-CDo/TnZ5RywSOVI/AAAAAAAAAD4/9irfxqw6kf8/s1600/6.png" imageanchor="1" style=""&gt;&lt;img border="0" height="326" width="400" src="http://2.bp.blogspot.com/-ZmDywAz-CDo/TnZ5RywSOVI/AAAAAAAAAD4/9irfxqw6kf8/s400/6.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-5794107462548632593?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/5794107462548632593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/09/lousy-tutorial-to-c-drag-and-drop.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/5794107462548632593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/5794107462548632593'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/09/lousy-tutorial-to-c-drag-and-drop.html' title='A lousy tutorial to C# drag and drop'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-27jr8bL3FHc/TnZ41-YaJLI/AAAAAAAAADQ/czEG75lL0Bw/s72-c/1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-5250601785721774528</id><published>2011-07-17T16:25:00.001+02:00</published><updated>2011-07-17T16:29:13.960+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithms'/><title type='text'>Quicksort partitioning</title><content type='html'>&lt;p&gt;During my years in school and at university I was always exposed to only one algorithm of quicksort partitioning. Let's take a look at some ways to partition a list for sorting.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Quicksort&lt;/h1&gt;&lt;p&gt;Quicksort itself works by taking a list, picking an element from the list which is referred to as the "pivot" and splitting the list into two sub lists, the first containing all the elements smaller than the pivot and the second containing all the elements greater than the pivot. Once you have these two sub lists you can sort each one independently of the other since elements in one list will not be moved into the other after the sort is complete.&lt;/p&gt;&lt;p&gt;This splitting into two lists is called "partitioning". Partitioning once will not sort the list but it will allow you to either use a different sorting algorithm on each sub list (partition) or to recursively partition the two partitions until you end up with a partition of 1 or 0 elements, which is necessarily sorted.&lt;/p&gt;&lt;p&gt;For example, partitioning the list [7,3,6,4,1,7,3] using 4 as a pivot will give us a first partition of [3,1,3] and a second partition of [7,6,7]. The pivot itself, along with other duplicates of it, may or may not go in one of the partitions, depending on how the partitioning is done. If it does not go into one of the partitions, then the sort will place the pivot between the 2 partitions after they have been sorted.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Partitioning by filtering&lt;/h2&gt;&lt;p&gt;The most intuitive way to partition is by creating 2 new lists, going through the unsorted list and copying elements from the unsorted list into one of the 2 lists. This is memory expensive however as you end up needing twice as much space as the unsorted list takes. The following partitioning algorithms are "in-place" and hence do not need any new lists.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Partitioning by moving the pivot&lt;/h2&gt;&lt;p&gt;This is the partitioning algorithm I was familiar with at school. It's quite intuitive but slow when compared to the next algorithm. The way this works is by putting the pivot into its sorted place, that is, the place where it will be after the whole list has been sorted. All the elements smaller than the pivot will be on its left and all the elements larger than the pivot will be on its right. Therefore you would have created 2 partitions, the left side of the pivot and the right side.&lt;/p&gt;&lt;p&gt;The algorithm uses a pivot pointer which keeps track of where the pivot is and an index pointer which is used to compare the pivot to other elements. The pivot pointer starts by being at the right end of the list (you can choose a pivot and swap it with the last element if you don't want to stick to the element which happens to be there) and the index pointer starts by being at the left end of the list. The index moves towards the pivot pointer until it encounters an element which is not on the correct side of the pivot, upon which the index and the pivot and swapped and the the index pointer and pivot pointer swap locations. Once the index pointer and pivot pointer meet, the pivot is in its sorted location and the left and right side of the pivot are partitions.&lt;/p&gt;&lt;br /&gt;Pseudo code:&lt;br /&gt;&lt;pre&gt;function partition(arr, left, right)&lt;br /&gt;  pivotPtr = right&lt;br /&gt;  indexPtr = left&lt;br /&gt;  while pivotPtr != indexPtr&lt;br /&gt;    if indexPtr &amp;lt; pivotPtr //if index pointer is to the left of the pivot&lt;br /&gt;      while arr[indexPtr] &amp;lt;= arr[pivotPtr] and indexPtr &amp;lt; pivotPtr&lt;br /&gt;        indexPtr++ //move index pointer towards the pivot&lt;br /&gt;      if indexPtr &amp;lt; pivotPtr&lt;br /&gt;        swap(arr[indexPtr], arr[pivotPtr])&lt;br /&gt;        swap(indexPtr, pivotPtr)&lt;br /&gt;    else //if index pointer is to the right of the pivot&lt;br /&gt;      while arr[indexPtr] &amp;gt;= arr[pivotPtr] and indexPtr &amp;gt; pivotPtr&lt;br /&gt;        indexPtr-- //move index pointer towards the pivot&lt;br /&gt;      if indexPtr &amp;gt; pivotPtr&lt;br /&gt;        swap(arr[pivotPtr], arr[indexPtr])&lt;br /&gt;        swap(pivotPtr, indexPtr)&lt;br /&gt;  return pivotPtr&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Partitioning by dividing&lt;/h2&gt;&lt;p&gt;In the previous partitioning algorithm, we had to constantly swap the pivot in order to eventually put it in its place. This is however unnecessary as partitioning does not require the pivot to be in its sorted place, only that we have 2 partitions, even if the pivot itself is in one of the partitions (it doesn't matter in which one as it could be eventually placed in its sorted place in either partition).&lt;/p&gt;&lt;p&gt;This time we will not care where the pivot is, as long as we know its value. We will need 2 pointers, a high and a low pointer, which will be moving towards each other. The low pointer will expect to encounter only elements which are smaller than the pivot and the high point will expect to encounter only elements which are larger than the pivot. When both pointers encounter a wrong element, they swap the elements and continue moving towards each other. When they eventually meet, all the elements to the left of the meeting point will be smaller than or equal to the pivot and all the elements to the right of the meeting point will be greater than or equal to the pivot.&lt;br /&gt;Since both pointers will be moving toward each other before swapping, this algorithm will do less swaps than the previous one and hence will be much faster. In fact a simple experiment will show that it does half the number of swaps.&lt;/p&gt;&lt;br /&gt;Pseudo code:&lt;br /&gt;&lt;pre&gt;function partition(arr, left, right, pivot)&lt;br /&gt;  lo = left&lt;br /&gt;  hi = right&lt;br /&gt;  while lo &amp;lt; hi&lt;br /&gt;    while arr[lo] &amp;lt;= pivot and lo &amp;lt; hi&lt;br /&gt;      lo++ //move low pointer towards the high pointer&lt;br /&gt;    while arr[hi] &amp;gt;= pivot and hi &amp;gt; lo&lt;br /&gt;      hi-- //move high pointer towards the low pointer&lt;br /&gt;    if lo &amp;lt; hi&lt;br /&gt;      swap(arr[lo], arr[hi])&lt;br /&gt;  /*&lt;br /&gt;    Since the high pointer moves last, the meeting point should be on an element that is greater than the pivot, that is, the meeting point marks the start of the second partition.&lt;br /&gt;    However if the pivot happens to be the maximum element, the meeting point will simply be the last element and hence will not have any significant meaning.&lt;br /&gt;    Therefore we need to make sure that the returned meeting point is where the starting point of the second partition is, including if the second partition is empty.&lt;br /&gt;  */&lt;br /&gt;  if arr[lo] &amp;lt; pivot&lt;br /&gt;    return lo+1&lt;br /&gt;  else&lt;br /&gt;    return lo&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-5250601785721774528?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/5250601785721774528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/07/quicksort-partitioning.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/5250601785721774528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/5250601785721774528'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/07/quicksort-partitioning.html' title='Quicksort partitioning'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-4794682851612002438</id><published>2011-06-02T10:58:00.000+02:00</published><updated>2011-06-02T10:58:53.717+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='proofs'/><category scheme='http://www.blogger.com/atom/ns#' term='maths'/><category scheme='http://www.blogger.com/atom/ns#' term='logic'/><title type='text'>Negation Introduction</title><content type='html'>When I was in university, one of my favorite units was Mathematics of Discrete Structures lectured by Dr Gordon Pace. In propositional logic, we learned about the negation introduction rule of inference which was this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;P =&gt; Q, P =&gt; ~Q&lt;br /&gt;---------------&lt;br /&gt;     ~P&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and which was used like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1.  | P   Assumed&lt;br /&gt;... | ...&lt;br /&gt;10. | Q&lt;br /&gt;&lt;br /&gt;11. | P   Assumed&lt;br /&gt;... | ...&lt;br /&gt;20. | ~Q&lt;br /&gt;21. ~P   Negation introduction from lines 1-10 and 11-20&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In other words, if P implies that Q is true and also P implies that Q is not true, then P must itself not be true.&lt;br /&gt;&lt;br /&gt;I never actually understood the logic behind it however. We were told that this how a proof by contradiction works. An example of a proof by contradiction, in words, is this:&lt;br /&gt;&lt;blockquote&gt;If it were raining, the streets would be wet. But the streets are not wet. Therefore it is not raining.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The fact that if a particular proposition is true, it would lead to another proposition which we know is false, implies that the first proposition must itself be false.&lt;br /&gt;&lt;br /&gt;The problem with the rule of inference we used for negation introduction is that the way I interpret it linguistically is not at all how a proof by contradiction is usually told. If we had to turn the rule of inference into words, it would be this:&lt;br /&gt;&lt;blockquote&gt;If P implies that something is both true and false, then P is itself false.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;A rule of inference which is closer to a proof by contradiction would be this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Q, P =&gt; ~Q&lt;br /&gt;----------&lt;br /&gt;    ~P&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which would be used like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;...&lt;br /&gt;10. Q&lt;br /&gt;11. | P    Assumed&lt;br /&gt;... | ...&lt;br /&gt;20. | ~Q&lt;br /&gt;21. ~P     Negation introduction from lines 10 and 11-20&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is closer to a proof by contradiction.&lt;br /&gt;&lt;blockquote&gt;If P implies something which is not true, then P itself is not true.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The question is, can we use this new rule of inference instead of the usual one?&lt;br /&gt;&lt;br /&gt;When can the usual rule of inference be more powerful than the proposed one? Only when both Q and ~Q can ONLY be derived using P. Hence P must be assumed in both cases which cannot be done with the proposed rule of inference.&lt;br /&gt;&lt;br /&gt;But this can easily be solved by using the lemma Q /\ ~Q =&gt; X and tautologies. If P can derive both Q and ~Q, then we can also derive Q /\ ~Q from which further derive anything we want, including something false. Worst case, if we don't know what to derive which is false, we can derive the negation of a tautology, such as ~(A =&gt; A). A =&gt; A is a tautology and we can always just insert it in a proof.&lt;br /&gt;&lt;br /&gt;So using this trick, we'd do the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;1.  | P          Assumed&lt;br /&gt;... | ...&lt;br /&gt;10. | Q&lt;br /&gt;... | ...&lt;br /&gt;20. | ~Q&lt;br /&gt;21. | Q /\ ~Q    Conjunction introduction from lines 10 and 20&lt;br /&gt;22. | ~(A =&gt; A)  Q /\ ~Q =&gt; X lemma from line 21&lt;br /&gt;23. A =&gt; A       A =&gt; A lemma&lt;br /&gt;24. ~P           Negation introduction from lines 1-22 and 23&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And therefore, where ever we can use the usual rule of inference, we can also use the proposed rule of inference.&lt;br /&gt;&lt;br /&gt;QED :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-4794682851612002438?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/4794682851612002438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/06/negation-introduction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/4794682851612002438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/4794682851612002438'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/06/negation-introduction.html' title='Negation Introduction'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-4430117815651099962</id><published>2011-04-22T09:47:00.000+02:00</published><updated>2011-04-22T09:47:12.857+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computer science'/><category scheme='http://www.blogger.com/atom/ns#' term='essay'/><title type='text'>Artificial Intelligence</title><content type='html'>This is an essay I wrote back when I was in university about artificial intelligence. I decided to put it up in my geek blog. Enjoy! By the way, I later learned about the halting problem which makes my last paragraph impossible to be realized if the program is expected to be right every time.&lt;br /&gt;&lt;br /&gt;Artificial Intelligence&lt;br /&gt;&lt;br /&gt;Intelligence is the ability to do something without previously knowing how and use the new knowledge on other problems, or rather, to learn without being taught. Someone who is stupid and therefore not intelligent is someone who requires instructions in order to do (apparently) everything, much like a computer. So what is artificial intelligence? How can a computer simulate this process?&lt;br /&gt;&lt;br /&gt;Well if this is possible then it would imply the end of programming, since essentially there would only be one program which will learn how to do anything the user wants. So basically an intelligent program has 3 phases: You tell it what you want it to do, it figures out how to do it and finally does it. The program can decide that it cannot do what it was told. However the most intelligent program is that which accepts the most specifications. It can also decide that it does not have the necessary resources to do what it was told. Again, the most intelligent program is the one which does the most things with the resources it has.&lt;br /&gt;&lt;br /&gt;Learning requires external information. Therefore the program must be allowed to gather information about the problem and perhaps completed research by other sources. This is best accomplished via the Internet, although elicitation with the user is a must. The most intelligent program is that which makes best use of past knowledge and requiring least new knowledge (the ability to reuse knowledge). Of course if the program does not gather new information and relies too much on past knowledge it will end up being “closed minded” and this is not desirable as it will result in a closed region of knowledge with no new ideas.&lt;br /&gt;&lt;br /&gt;Just like a computer is built without knowing what it’s going to be used for, so must be an intelligent program. A truly intelligent program would not be made for specific tasks such as recognising images or playing a game. It should be the most reusable application ever programmed. It should not be simply a part of another program, but be the entire program (except perhaps the interface).&lt;br /&gt;&lt;br /&gt;So it seems that artificial intelligence means a program which translates specifications to solutions without the programmer knowing the solution. The key point here is that the programmer doesn’t know the solution (OK, no one in the development process knows it). This facilitates programming since the programmer need not know the solution before writing the program but rather leaves it to the program to find the solution. It’s also great when we as humans still have not found a solution (or an efficient one) to a particular problem.&lt;br /&gt;&lt;br /&gt;What may the future hold for AI? As already mentioned, one day there will be a published algorithm for true AI which is able to learn how to solve any solvable problem, given a specification which has a high level of expressiveness. The first to benefit would be the humanoid robots which in turn would benefit humans in a variety of ways, which need not be mentioned. However will this mean the end of all human jobs, skilled and unskilled alike? Probably what will happen is that the developed countries will slow down the development of AI in the market in order to preserve jobs. But it might be possible for undeveloped countries to acquire some intelligent robots (through missionaries for example) which will help in some way or another. Perhaps in the developed world some hard to find professions will be filled in by robots, but I doubt they will be popular. However it can be possible that one day no one will work anymore and communism will take over as financial classes will be eradicated. All work will be done by robots and people will live a leisurely life, receiving provisions and resources equally. I doubt this will be allowed.&lt;br /&gt;&lt;br /&gt;One application of AI I would pursue would be that of fabricating assignments. It would accept the specs of the assignment in raw format as given to the student, possibly with the addition of some course notes for reference, and the ID number of the student. The routine would understand the spec and using the ID number will generate a unique assignment with compiled code (if any) and documentation and comments. If I were to manage to realise such a routine, I would charge my fellow class mates to write their assignments, except that I wouldn’t do anything except feed the program the spec and ID number. Since every student will receive a unique assignment there will be no fear of plagiarism and detecting that the assignment was generated would be practically impossible unless the lecturers would obtain a copy of the routine and compare the given work with the generated one. Come to think of it, a uniquely generated id number would be better. The reason why AI makes sense to be used is because of the shear difficulty to find an algorithm which solves the problem.&lt;br /&gt;&lt;br /&gt;Another application would be the semantic interpretation of a given code. The program would accept a given piece of code (given that it is accepted by the compiler) and produce a description in simple English what happens when it executes, at a given level of abstraction. Of course this can be extended to the interpretation of a given executable file. If this is possible then viruses and all malware would be easily detected with no need for updates. The other way round would also be nice where given a description in simple English, the program generates annotated code, ready to be compiled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-4430117815651099962?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/4430117815651099962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/04/artificial-intelligence.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/4430117815651099962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/4430117815651099962'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/04/artificial-intelligence.html' title='Artificial Intelligence'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-2296134667496217931</id><published>2011-04-21T12:04:00.000+02:00</published><updated>2012-02-07T19:26:17.306+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>JQuery event / manipulation not working</title><content type='html'>This is just a silly mistake I made which I thought I should share with the internetz. When assigning JQuery events to html elements, be sure to do it only after they have been loaded. If you just put them straight into a script file the elements wouldn't have loaded when it executes and hence the event won't work.&lt;br /&gt;&lt;br /&gt;Make sure that all html DOM manipulation is done after the html loads by putting the javascript code inside a&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$(document).ready(function() {&lt;br /&gt;   event and manipulation stuff here :D&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-2296134667496217931?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/2296134667496217931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/04/jquery-event-manipulation-not-working.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/2296134667496217931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/2296134667496217931'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/04/jquery-event-manipulation-not-working.html' title='JQuery event / manipulation not working'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-7807072011496832050</id><published>2011-04-21T11:54:00.000+02:00</published><updated>2011-04-21T11:54:31.012+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='photoshop'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Photoshop slices using divs creates gaps</title><content type='html'>If you've ever used Photoshop to create websites by drawing them and then slicing out the buttons and if you've ever used divs and css positioning to layout the slicing (done automatically by Photoshop, just follow &lt;a href="http://www.daniweb.com/web-development/web-design/graphics-and-multimedia/threads/217982"&gt;this&lt;/a&gt;) then you probably found out that something like this happens:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-GOT_8I2wYTU/Ta_4rwn5cEI/AAAAAAAAABs/3kZ90J0h58I/s1600/gappedslices.png" imageanchor="1" style=""&gt;&lt;img border="0" height="320" width="186" src="http://2.bp.blogspot.com/-GOT_8I2wYTU/Ta_4rwn5cEI/AAAAAAAAABs/3kZ90J0h58I/s320/gappedslices.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This happened to me whilst doing my personal website (www.marctanti.com). The solution was found &lt;a href="http://www.webmasterworld.com/forum21/11586.htm"&gt;here&lt;/a&gt;. Apparently this happens because when the doctype of the html page is set to strict, images are by default set to display:inline which makes them vertically aligned so that the bottom of the image is in line with where the base line of the text is. In the case of sliced web pages, the slices are placed inside divs so the images are aligned with where the base line of text inside the div would be if there was any. But the divs make room for the &amp;quot;descenders&amp;quot; of text, that is, the extra room needed to display the bottom of the letters 'y' and 'g' for example. Therefore the images will not be aligned with the very bottom of the divs.&lt;br /&gt;&lt;br /&gt;So to fix this problem we need to make the images aligned to the very bottom of the containing divs by setting the display css of each slice to block. I gave each slice image a class attribute called slice and then added the following css:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;.slice&lt;br /&gt;{&lt;br /&gt; display:block;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That fixed it.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-6qJbOqhBs2s/Ta_-sx3STpI/AAAAAAAAAB0/KS3dWSK0ZZI/s1600/gaplessslices.png" imageanchor="1" style=""&gt;&lt;img border="0" height="320" width="184" src="http://3.bp.blogspot.com/-6qJbOqhBs2s/Ta_-sx3STpI/AAAAAAAAAB0/KS3dWSK0ZZI/s320/gaplessslices.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-7807072011496832050?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/7807072011496832050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/04/photoshop-slices-using-divs-creates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/7807072011496832050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/7807072011496832050'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/04/photoshop-slices-using-divs-creates.html' title='Photoshop slices using divs creates gaps'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-GOT_8I2wYTU/Ta_4rwn5cEI/AAAAAAAAABs/3kZ90J0h58I/s72-c/gappedslices.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-546981085594554787</id><published>2011-03-30T10:30:00.075+02:00</published><updated>2011-07-04T15:46:17.169+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='databases'/><title type='text'>Database Normalization (1-3 NF)</title><content type='html'>This is a tutorial for those who are confused about the normal forms due to the extreme confusion you find on the web about the subject. If you want to know what normalization is and why to do it, wikipedia has a great article detailing this information:&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Database_normalization"&gt;http://en.wikipedia.org/wiki/Database_normalization&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;1NF&lt;/h1&gt;1NF is arguably the most ambiguous and confusing normal form on the web. The first normal form is just about making multi-valued fields organized into multiple rows. There are two types of multi-valued fields in unnormalized tables:&lt;br /&gt;&lt;br /&gt;This-&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;Id&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;Subject 1&lt;/th&gt;&lt;th&gt;Subject 2&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;And this-&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;Id&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;Subjects&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;Charms, Potions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;Charms, Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Or as is shown in most examples, this-&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;Id&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;In both cases we are tying to shove in a list of values,&amp;nbsp;that is&amp;nbsp;a one-to-many or many-to-many relationship with the row, into the row itself. For reasons detailed in the wikipedia article, this should be fixed by creating a separate row for each value and repeating the values in the others fields, like so:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;Id&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The table is now in 1NF were it not for the primary key losing its uniqueness. The id field&amp;nbsp;must be unique in order to identify each distinct student. To solve this we can do one of two things:&lt;br /&gt;&lt;br /&gt;Either we create an additional key field for the subjects and make the primary key of the whole table be a composite key of both student and subject ids, thus making the composite&amp;nbsp;key unique-&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Or we could just&amp;nbsp;prepare for the&amp;nbsp;other&amp;nbsp;normal forms&amp;nbsp;and start splitting the tables now as is usually done in examples-&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Notice that we still need to make the foreign key in the students table part of the primary key in order to preserve uniqueness. If you're wondering why we didn't use a weak&amp;nbsp;entity (bridge table / junction table), that's because it's done in 2NF.&lt;br /&gt;&lt;br /&gt;If we had more than one multi-valued field, we'd just create a Cartesian product, like so:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Resulting in 3 tables:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div style="border-bottom-style: solid; border-left-style: solid; border-right-style: solid; border-top-style: solid;"&gt;&lt;h2&gt;Complete example:&lt;/h2&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;Id&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;SubjId&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;th&gt;RoomHall&lt;/th&gt;&lt;th&gt;TeacId&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Turns into:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;th&gt;RoomHall&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Notice that the room is assumed to be dependant on the subject such that each subject is taught in its own room.&lt;br /&gt;&lt;br /&gt;We may opt to leave the table as it is as it quite complex to break down into smaller tables without any guidance. However if we are to break the table down, the room information would be included in with the subject table since we said that the room is dependant on it, yielding the following:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;th&gt;RoomHall&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;h1&gt;2NF&lt;/h1&gt;2NF is only applicable on tables with composite keys. If a table does not have a composite key, then it is already in 2NF. To make a table in 2NF, first you make sure it is in 1NF and then you split it into separate tables depending on which part of the composite key the fields depend on. For example in the students' table above, the&amp;nbsp;student name&amp;nbsp;does not depend on the subject id,&amp;nbsp;it depends only on part of the composite key, that is, the student id. So the student name field should go into a separate table which describes the students (together with the primary key of course).&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;And there is it, the weak entity we are so used to in many to many relationships.&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom-style: solid; border-left-style: solid; border-right-style: solid; border-top-style: solid;"&gt;&lt;h2&gt;Complete example (following from previous):&lt;/h2&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Turns into:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Hence yielding:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Student&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Harry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Ron&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;th&gt;RoomHall&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Teacher&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Filius&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Slughorn&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Notice that if in 1NF we did not break down the table, we'd result with the same set of tables by now.&lt;/div&gt;&lt;br /&gt;&lt;h1&gt;3NF&lt;/h1&gt;3NF is the normal form we are used to. All we do is check that every field in a 2NF table depends directly on the primary key. If it doesn't or if it depends on a non-primary key field, you place it in its own table. For example if we had the following table:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;th&gt;RoomHall&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The RoomHall field is directly dependent on the Room field and not on the SubjId primary key field, so the RoomHall field should go into a table on its own together with the Room field. In fact the room where the subject is thought is not a direct property of the subjects entity but is an entity on its own and hence should be separated into a rooms entity and only referenced by a foreign key.&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;&lt;th&gt;Subject&lt;/th&gt;&lt;th&gt;Room&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Charms&lt;/td&gt;&lt;td&gt;101&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Potions&lt;/td&gt;&lt;td&gt;202&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;u&gt;Room&lt;/u&gt;&lt;/th&gt;&lt;th&gt;RoomHall&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;101&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;202&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div style="border-bottom-style: solid; border-left-style: solid; border-right-style: solid; border-top-style: solid;"&gt;&lt;h2&gt;Complete example (following from previous):&lt;/h2&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;Subject&lt;/th&gt;       &lt;th&gt;Room&lt;/th&gt;       &lt;th&gt;RoomHall&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;Charms&lt;/td&gt;       &lt;td&gt;101&lt;/td&gt;       &lt;td&gt;A&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;Potions&lt;/td&gt;       &lt;td&gt;202&lt;/td&gt;       &lt;td&gt;B&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;Turns into:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;Subject&lt;/th&gt;       &lt;th&gt;Room&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;Charms&lt;/td&gt;       &lt;td&gt;101&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;Potions&lt;/td&gt;       &lt;td&gt;202&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;Room&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;RoomHall&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;101&lt;/td&gt;       &lt;td&gt;A&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;202&lt;/td&gt;       &lt;td&gt;B&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;Hence yielding:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;1&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;2&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;3&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;1&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;2&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;3&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;StudId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;Student&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;Harry&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;Ron&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;SubjId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;Subject&lt;/th&gt;       &lt;th&gt;Room&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;Charms&lt;/td&gt;       &lt;td&gt;101&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;Potions&lt;/td&gt;       &lt;td&gt;202&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;Room&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;RoomHall&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;101&lt;/td&gt;       &lt;td&gt;A&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;202&lt;/td&gt;       &lt;td&gt;B&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;       &lt;th&gt;&lt;u&gt;TeacId&lt;/u&gt;&lt;/th&gt;       &lt;th&gt;Teacher&lt;/th&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;1&lt;/td&gt;       &lt;td&gt;Filius&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;2&lt;/td&gt;       &lt;td&gt;Slughorn&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td&gt;3&lt;/td&gt;       &lt;td&gt;Snape&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;h1&gt;Links&lt;/h1&gt;&lt;a href="http://portal.dfpug.de/dFPUG/Dokumente/Partner/Hentzenwerke/Visual%20FoxPro%20Certification%20Exam%20Study%20Guide%20Chapter%2002.pdf"&gt;http://portal.dfpug.de/dFPUG/Dokumente/Partner/Hentzenwerke/Visual%20FoxPro%20Certification%20Exam%20Study%20Guide%20Chapter%2002.pdf&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-546981085594554787?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/546981085594554787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/03/database-normalization-1-2-3-nf.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/546981085594554787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/546981085594554787'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/03/database-normalization-1-2-3-nf.html' title='Database Normalization (1-3 NF)'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-7096265146089988321</id><published>2011-03-14T16:36:00.007+01:00</published><updated>2011-03-30T10:35:58.021+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='databases'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>Reading Related Tables As Nested Rows</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Problem&lt;/span&gt;&lt;br /&gt;A problem I used to face with relational databases is how to handle 1-to-many or many-to-many rows in SQL select statements. Let's say you have 2 tables with a many-to-many relationship between them, such as a Movies table and an Actors table. How do I present a list of movies together with their associated actors? &lt;br /&gt;&lt;br /&gt;The naive way to do this is by using nested loops with a query for movies in the top loop and a query for actors in the second loop. In PHP it would look something like... &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: php"&gt;$moviesResult = mysql_query("SELECT id, title FROM movies"); &lt;br /&gt;while($moviesRow = mysql_fetch_assoc($result)) &lt;br /&gt;{ &lt;br /&gt;    echo("&amp;lt;h1&amp;gt;" . $moviesRow['title'] . "&amp;lt;/h1&amp;gt;"); &lt;br /&gt;&lt;br /&gt;    echo("&amp;lt;ul&amp;gt;"); &lt;br /&gt;    $actorsResult = mysql_query("SELECT actors.name FROM actors INNER JOIN movies_actors ON actors.id = movies_actors.actorid WHERE movies_actors.movieid = " . $moviesRow['id'] . ";"); &lt;br /&gt;    while($actorsRow = mysql_fetch_assoc($actorsResult)) &lt;br /&gt;    { &lt;br /&gt;        echo("&amp;lt;li&amp;gt;" . $actorsRow['name'] . "&amp;lt;/li&amp;gt;"); &lt;br /&gt;    } &lt;br /&gt;    echo("&amp;lt;/ul&amp;gt;"); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This approach however will kill your database. Ideally you should minimize the number of queries sent. &lt;br /&gt;&lt;br /&gt;Another approach would be to join the movies table with the actors table and then read it with nested loops. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: php"&gt;$result = mysql_query("SELECT movies.id AS id movies.title AS title, actors.name AS actor FROM movies INNER JOIN movies_actors ON movies.id = movies_actors.movie INNER JOIN actors ON actors.id = movies_actors.actor"); &lt;br /&gt;$row = mysql_fetch_assoc($result); &lt;br /&gt;while($row) &lt;br /&gt;{ &lt;br /&gt;    $currMovieId = $row['id']; &lt;br /&gt;    echo("&amp;lt;h1&amp;gt;" . $row['title'] . "&amp;lt;/h1&amp;gt;"); &lt;br /&gt;    echo("&amp;lt;ul&amp;gt;"); &lt;br /&gt;    do &lt;br /&gt;    { &lt;br /&gt;        echo("&amp;lt;li&amp;gt;" . $row['name'] . "&amp;lt;/li&amp;gt;"); &lt;br /&gt;    } while ($row = mysql_fetch_assoc($result) &amp;amp;&amp;amp; $row['id'] == $currMovieId);&lt;br /&gt;    echo("&amp;lt;/ul&amp;gt;"); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This works but as soon as you add another table to the join, determining which rows contain new information can be a nightmare, not to mention all the rows which just contain repeated information due to the cartesian product. For example: &lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;Title&lt;/th&gt;&lt;th&gt;Actor&lt;/th&gt;&lt;th&gt;Genre&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Keanu Reeves&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Laurence Fishburne&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Adventure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Are we supposed to receive all those rows just to display the below? &lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;The Matrix&lt;/td&gt;&lt;td&gt;Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Action, Adventure, Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;The Matrix Reloaded&lt;/td&gt;&lt;td&gt;Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Action, Adventure, Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;The Matrix Revolutions&lt;/td&gt;&lt;td&gt;Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss&lt;/td&gt;&lt;td&gt;Action, Adventure, Sci-Fi&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Solution&lt;/span&gt;&lt;br /&gt;The best solution I found is a hybrid of the above 2 solutions. You make a different query for each table and then read all the rows returned by each query, placing the information in the list it belongs to. &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: php"&gt;$moviesResult = mysql_query("SELECT id, title FROM movies;"); &lt;br /&gt;$actorsResult = mysql_query("SELECT movies_actors.movieid AS movieid, actors.name AS name FROM actors INNER JOIN movies_actors ON actors.id = movies_actors.actorid;"); &lt;br /&gt;$genresResult = mysql_query("SELECT movies_genres.movieid AS movieid, genres.name AS name FROM genres INNER JOIN movies_genres ON genres.id = movies_genres.genreid;"); &lt;br /&gt;&lt;br /&gt;$actorRow = mysql_fetch_assoc($actorsResult); &lt;br /&gt;$genreRow = mysql_fetch_assoc($genresResult); &lt;br /&gt;while($movieRow = mysql_fetch_assoc($moviesResult)) &lt;br /&gt;{ &lt;br /&gt;    $currMovieId = $movieRow['id']; &lt;br /&gt;    echo("&amp;lt;h1&amp;gt;" . $movieRow['title'] . "&amp;lt;/h1&amp;gt;"); &lt;br /&gt;&lt;br /&gt;    echo("&amp;lt;ul&amp;gt;"); &lt;br /&gt;    while ($actorRow &amp;amp;&amp;amp; $actorRow['movieid'] == $currMovieId) &lt;br /&gt;    { &lt;br /&gt;        echo("&amp;lt;li&amp;gt;" . $row['name'] . "&amp;lt;/li&amp;gt;"); &lt;br /&gt;        $actorRow = mysql_fetch_assoc($actorsResult); &lt;br /&gt;    } &lt;br /&gt;    echo("&amp;lt;/ul&amp;gt;"); &lt;br /&gt;&lt;br /&gt;    echo("&amp;lt;ul&amp;gt;"); &lt;br /&gt;    while ($genreRow &amp;amp;&amp;amp; $genreRow['movieid'] == $currMovieId) &lt;br /&gt;    { &lt;br /&gt;        echo("&amp;lt;li&amp;gt;" . $row['name'] . "&amp;lt;/li&amp;gt;"); &lt;br /&gt;        $genreRow = mysql_fetch_assoc($genresResult); &lt;br /&gt;    } &lt;br /&gt;    echo("&amp;lt;/ul&amp;gt;"); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this way we only make 3 queries, equal to the number of tables, and we only read as many rows as needed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-7096265146089988321?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/7096265146089988321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/03/reading-related-tables-as-nested-rows.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/7096265146089988321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/7096265146089988321'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/03/reading-related-tables-as-nested-rows.html' title='Reading Related Tables As Nested Rows'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-9220851903183041486</id><published>2011-03-13T20:01:00.028+01:00</published><updated>2011-03-30T10:36:17.792+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='databases'/><title type='text'>SQL Joins Tutorial</title><content type='html'>This is a simple tutorial aimed towards those who, like me, completely misunderstood how to, and why to, use joins in SQL. It is not meant to be an advanced reference but a tutorial for beginners who know some SQL but can't understand joins.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Huh?&lt;/span&gt;&lt;br /&gt;Let's say that you have a database with tables which are related by foreign keys. For example, a Customers table, a Products table and an Orders table. Each row in the Orders table is linked to a row in the Customers table (the customer who made the order) and to a row in the Products table (the product which was ordered).&lt;br /&gt;&lt;br /&gt;Now let's say that you want to query the database to view all the rows in the Orders table but with the customer's name and product's name instead of their primary key. If you learned SQL the same way I did, you'd probably do something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: sql"&gt;SELECT orders.date, customers.name, products.name&lt;br /&gt;FROM orders, customers, products&lt;br /&gt;WHERE orders.customer = customers.id AND orders.product = products.id;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is called an implicit join. In fact you are doing an unconditioned join between all 3 tables and then just filtering out the joined rows which are not made of related table rows. What does this mean?&lt;br /&gt;&lt;br /&gt;If our 3 tables contain the following data:&lt;br /&gt;&lt;br /&gt;Orders:&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;Customer&lt;/th&gt;&lt;th&gt;Product&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2/02/02&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Customers:&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Products:&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;Then the query will cause this to happen:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Movies.Date&lt;/th&gt;&lt;th&gt;Customers.Name&lt;/th&gt;&lt;th&gt;Products.Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;And after generating all that it will then select the rows which make sense relation wise, according to the WHERE statement.&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Movies.Date&lt;/th&gt;&lt;th&gt;Customers.Name&lt;/th&gt;&lt;th&gt;Products.Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The big table is called a Cartesian product, which means that all possible combinations of rows between the tables are created, yielding a number of rows equal to the multiplication of the number of rows in each table (3 * 3 * 3 = 27 in this case). As you can tell, this will get really huge really quickly as the table get bigger.&lt;br /&gt;&lt;br /&gt;Enter explicit joins.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Joins&lt;/span&gt;&lt;br /&gt;In SQL, the FROM statement doesn't mean "a list of tables used in the SELECT statement". In the FROM statement you mention just one table. This table could either be one of the tables you created in the database or a "custom" table, such as one which is a joined version of several tables. The JOIN statement in SQL is not a keyword on par with the FROM statement, as I used to think due to the way it is indented in most tutorials I've seen. It is in fact a binary operator between 2 tables, just like "+" and "=" as binary operators.&lt;br /&gt;&lt;br /&gt;The JOIN operator takes 2 tables and returns a new table, which is a joined version of the 2 tables. You can then join another table to that new table and keep on adding more tables to the "composite" table. There are several joins available in standard SQL which will be described later, but if we should use the INNER JOIN type in an example, this is how joins are used in general:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: sql"&gt;SELECT orders.date, customers.name, products.name&lt;br /&gt;FROM (orders INNER JOIN customers ON orders.customer = customers.id) INNER JOIN products ON orders.product = products.id;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see, the join is used between tables and can even be bracketed in order to state which tables should be joined up first. The ON statement is used to immediately join up the rows which are related, avoiding the cartesian product table in the first place. This will therefore be processed much more efficiently as the third table will only be joined up after the first two tables have been joined correctly, rather than joining everything together without a condition.&lt;br /&gt;&lt;br /&gt;In the implicit join example, the tables where joined up with an inner join without the ON condition, hence losing all the advantage of joins. Now that you know how joins work, let's see what are the differences between the 4 join types described in w3schools.com.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Join types&lt;/span&gt;&lt;br /&gt;The main difference between the join types is how they handle rows which don't match the ON condition.&lt;br /&gt;&lt;br /&gt;INNER JOIN:&lt;br /&gt;Strictly follows the ON condition between tables such that any rows in one table which cannot be matched up with another row in the other table will be left out. This is the kind of join we are used to.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: sql"&gt;SELECT orders.date, customers.name, products.name&lt;br /&gt;FROM (orders INNER JOIN customers ON orders.customer = customers.id) INNER JOIN products ON orders.product = products.id;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;results in&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Movies.Date&lt;/th&gt;&lt;th&gt;Customers.Name&lt;/th&gt;&lt;th&gt;Products.Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;td&gt;Spam&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;As you can see, not all customers or all products where mentioned. Only the ones which were mentioned in the ORDERS table and hence were related in some way were returned.&lt;br /&gt;&lt;br /&gt;OUTER JOIN:&lt;br /&gt;This is where things get a bit hairy and hence require that you make an effort to understand. The outer join makes sure that all rows in both tables are returned, even if there is no matching row in the other table. What happens to those tables which have no matching rows? They are joined to NULL values. As long as they are returned, it doesn't matter what they're joined to right?&lt;br /&gt;&lt;br /&gt;You can also use LEFT JOIN and RIGHT JOIN to say whether you want to return all the rows of the table on the left of the join operator only or all the rows of the table on the right of the join operator only.&lt;br /&gt;&lt;br /&gt;Now in order to use these joins to create a complex joined table, you have to be sure that a join will not return columns with NULL values which will be used in an ON condition of another join.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: sql"&gt;SELECT orders.date, customers.name&lt;br /&gt;FROM orders RIGHT JOIN customers ON orders.customer = customers.id;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;results in&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Movies.Date&lt;/th&gt;&lt;th&gt;Customers.Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;John&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;td&gt;Michael&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;Terry&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;pre class="brush: sql"&gt;SELECT orders.date, products.name&lt;br /&gt;FROM orders RIGHT JOIN products ON orders.product = products.id;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;results in&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Movies.Date&lt;/th&gt;&lt;th&gt;Customers.Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;td&gt;cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;spam&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;pre class="brush: sql"&gt;SELECT orders.date, products.name, customers.name&lt;br /&gt;FROM (orders LEFT JOIN customers ON orders.customer = customers.id) RIGHT JOIN products ON orders.product = products.id;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;results in&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Movies.Date&lt;/th&gt;&lt;th&gt;Customers.Name&lt;/th&gt;&lt;th&gt;Products.Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;td&gt;cheese&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02/02/02&lt;/td&gt;&lt;td&gt;terry&lt;/td&gt;&lt;td&gt;parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;01/01/01&lt;/td&gt;&lt;td&gt;john&lt;/td&gt;&lt;td&gt;parrot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;03/03/03&lt;/td&gt;&lt;td&gt;terry&lt;/td&gt;&lt;td&gt;spam&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;As you can see, depending on how the outer joins are used, we can make a particular table return all its rows, even if it isn't related to any other table.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Final note&lt;/span&gt;&lt;br /&gt;I'd like to leave a few notes and links before concluding.&lt;br /&gt;&lt;br /&gt;First of all, what I said about the implicit join not being efficient next to an explicit one is not necessarily true since the SQL optimizer may fix it before executing it.&lt;br /&gt;&lt;br /&gt;Secondly, if you can avoid using brackets in the the joins it would be better as that will allow the SQL optimizer to make adjustments to the query without it having to make sure to preserve the precedence which you unneccessarily imposed.&lt;br /&gt;&lt;br /&gt;In a future post, I will describe a trick which I used to efficiently view multiple one-to-many related tables which I also had trouble with in SQL until recently. But for now I will leave you with these links:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.w3schools.com/sql/sql_join.asp"&gt;http://www.w3schools.com/sql/sql_join.asp&lt;/a&gt;&lt;br /&gt;&lt;a href="http://onlamp.com/pub/a/onlamp/2004/09/30/from_clauses.html"&gt;http://onlamp.com/pub/a/onlamp/2004/09/30/from_clauses.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html"&gt;http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-9220851903183041486?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/9220851903183041486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/03/sql-joins-tutorial.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/9220851903183041486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/9220851903183041486'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/03/sql-joins-tutorial.html' title='SQL Joins Tutorial'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-2597665486992411149</id><published>2011-02-13T21:36:00.001+01:00</published><updated>2011-02-13T21:42:45.326+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='genetic algorithm'/><category scheme='http://www.blogger.com/atom/ns#' term='library'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='computer science'/><title type='text'>Generic Genetic Algorithms</title><content type='html'>I have finally finished my C# generic genetic algorithm library which is based on my university thesis "A Generic Genetic Algorithm using Phenotype Building Functions" (&lt;a href="http://www.scribd.com/doc/48697452/A-Generic-Genetic-Algorithm-using-Phenotype-Building-Functions"&gt;http://www.scribd.com/doc/48697452/A-Generic-Genetic-Algorithm-using-Phenotype-Building-Functions&lt;/a&gt;). You can find it at &lt;a href="http://code.google.com/p/genericga/"&gt;http://code.google.com/p/genericga/&lt;/a&gt;. The wiki page explains how to use it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-2597665486992411149?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/2597665486992411149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2011/02/generic-genetic-algorithms.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/2597665486992411149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/2597665486992411149'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2011/02/generic-genetic-algorithms.html' title='Generic Genetic Algorithms'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-3467428494499137221</id><published>2010-07-28T15:45:00.000+02:00</published><updated>2010-07-29T20:25:48.908+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='proofs'/><category scheme='http://www.blogger.com/atom/ns#' term='maths'/><category scheme='http://www.blogger.com/atom/ns#' term='computer science'/><title type='text'>Cool proofs</title><content type='html'>When I was in university, our course had a forum that we maintained ourselves in which we posted anything which would be of help to each other or which we found worth sharing. At the time of writing this, the forum will soon be closed down and all of the information in it will be probably lost. I shall post here my geekiest post ever which was titled "Cool proofs" in which I posted 3 mathematical proofs used in computer science which I literally found cool. ^^&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Power set of an infinite set is uncountable&lt;/span&gt;&lt;br /&gt;By uncountable we mean that you cannot have a one to one mapping from a countable infinite set, usually the natural numbers to the uncountable one.&lt;br /&gt;&lt;br /&gt;For example the set of all integers is countable because there exists a bijective mapping from the natural numbers to the integers, for example:&lt;br /&gt;0 -&amp;gt; 0&lt;br /&gt;1 -&amp;gt; -1&lt;br /&gt;2 -&amp;gt; 1&lt;br /&gt;3 -&amp;gt; -2&lt;br /&gt;4 -&amp;gt; 2&lt;br /&gt;...&lt;br /&gt;That is, even numbers point to positive integers and odd numbers point to negatives. So for every integer there exists a natural number which points to it and every natural number points to an integer. So even though there appears to be more integers than natural numbers, in reality they are equal because they are both countable infinite sets.&lt;br /&gt;&lt;br /&gt;Now in order to show that the power set of an infinite set is uncountable we need to show that there exists at least one element of the power set which cannot be pointed by a natural number. Consider this random relation of natural numbers pointing to elements of the power set of all natural numbers:&lt;br /&gt;0 -&amp;gt; {}&lt;br /&gt;1 -&amp;gt; {1}&lt;br /&gt;2 -&amp;gt; {0, 1, 2}&lt;br /&gt;3 -&amp;gt; {1, 3}&lt;br /&gt;4 -&amp;gt; {3, 5}&lt;br /&gt;5 -&amp;gt; {1, 2, 3, 4}&lt;br /&gt;6 -&amp;gt; {100, 1000, 10000}&lt;br /&gt;...&lt;br /&gt;Notice that some natural numbers are pointing to sets which contain themselves and others do not. Lets call the numbers which point to themselves Selfish and the others Non-Selfish. For example 1, 2 and 3 are selfish whilst 0, 4, 5 and 6 are not. Given that the power set of all natural numbers contains every possible subset of natural numbers, it stands to reason that one of the subsets should happen to be the set of all Non-Selfish numbers in our relation. Let's call the natural number which points to the set of all Non-Selfish numbers 'd' and the set of all Non-Selfish numbers S. Since every natural number must either be a Selfish number or a Non-Selfish number, we can safely say that d itself is either a Selfish number or a Non-Selfish number. So what is it?&lt;br /&gt;&lt;br /&gt;If d is a Selfish number then it is an element of S. But only Non-Selfish numbers are elements of S.&lt;br /&gt;If d is a Non-Selfish number then it is not an element of S. But S contains all Non-Selfish numbers.&lt;br /&gt;Therefore we have reached a contradiction, because we have found an element which cannot be mapped by a natural number. Therefore it is impossible to make a bijective relation between the natural numbers and the power set of all natural numbers. Therefore the power set of an infinite set is uncountable.&lt;br /&gt;&lt;br /&gt;QED&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Set of all infinite length binary strings is uncountable&lt;/span&gt;&lt;br /&gt;Enumerate the infinite length binary strings in a table in some order. For example:&lt;br /&gt;0011111000110011...&lt;br /&gt;1011100101100100...&lt;br /&gt;1010101010010101...&lt;br /&gt;0000000000000000...&lt;br /&gt;...&lt;br /&gt;Now we can refer to a particular string by referring to its corresponding row number. We can also refer to a particular bit in the string by referring to a particular column number. Let B(r,c) be the bit in column c of the string in row r.&lt;br /&gt;&lt;br /&gt;If this set was countable, we can create a bijective mapping from the natural numbers to each and every binary string. But it is impossible to enumerate each and every infinite length binary string because no matter what order we use and no matter how many strings we include, it is always possible to find a string which is not included. Here's how:&lt;br /&gt;Consider the diagonal bits in the table, that is, consider B(i,i) for every natural number i. Construct a string, s, which is made of the diagonal bits, inverted. That is, s[i] = !B(i,i). Now for every string, there is at least one bit which is different from s, because the diagonal includes one bit from every string and s has that bit inverted. Given the previous table, s would be 1101...&lt;br /&gt;&lt;br /&gt;So no matter how many strings you enumerate (infinity included) there are always strings which are not included in the enumeration. Or conversely, no matter how you construct a relation of natural numbers pointing to the strings, there are always strings which are left out. Therefore the set of all infinite length binary strings is uncountable.&lt;br /&gt;&lt;br /&gt;QED&lt;br /&gt;&lt;br /&gt;Notice that for any power set, its elements can be encoded into binary strings, where each bit represents whether a particular element in the original set is in that subset. For example the power set of {1,2} is {{}, {1}, {2}, {1,2}} which can be represented as {00, 10, 01, 11} where the first bit says if 1 is in the set and the second says if 2 is in the set. Therefore if the set of all infinite length binary string was countable, the power set of an infinite set was also countable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;The halting problem&lt;/span&gt;&lt;br /&gt;The halting problem proves that it is impossible to construct an algorithm (program which always terminates) which will analyze any program and correctly answer if, given a particular input, will terminate. Here's how.&lt;br /&gt;&lt;br /&gt;Assume that such a program exists and can be used by simply calling the function Halt(p,i) which will return whether program p will terminate given input i. What we shall do is construct a program which will use Halt on itself and do the opposite. If this is possible than we have just found a case where Halt will fail, no matter what the implementation.&lt;br /&gt;&lt;br /&gt;Construct program D which is defined as:&lt;br /&gt;D(p) = if Halt(p,p) then infinite_loop else terminate&lt;br /&gt;Program D will take a program p, check if it halts when given itself as input and enter into an infinite loop if so or terminate otherwise. If this self input confuses you, think of the input to be a copy of the original program. So if I have written a compression program which takes other files and compresses them, I can copy the program and compress the copy, essentially giving the program itself as input.&lt;br /&gt;&lt;br /&gt;The reason we constructed such a funny program is that if we give D itself as input, the following will happen:&lt;br /&gt;D(D) = if Halt(D,D) then infinite_loop else terminate&lt;br /&gt;and as you can see, Halt will essentially check if D(D) will terminate, therefore checking if the whole program will terminate. But what does the program mean? The program will either terminate with itself as input or not, but if it terminates then Halt will return true, causing the program to enter an infinite loop, whilst if it does not terminate then Halt will return false, causing the program to terminate.&lt;br /&gt;&lt;br /&gt;So if we now call Halt on this program, by calling Halt(D,D), Halt will not be able to come up with a correct answer because D will check what the output will be and do the opposite. Notice that we will receive an answer, it is the same as that given in the if-condition, but it will obviously be the opposite of what will happen. Remember that Halt will call D(p) and pass D as input (instead of p) and that D as a program and D as an input are two separate 'files' which are copies of each other. Self reference can be detected by for example changing a global variable to know how many times a function has been called but&lt;br /&gt;a) A semantically equivalent function can be rewritten which avoids such tricks, yet results in the same problem.&lt;br /&gt;b) This means that some program-input pairs will not be accepted, which means that you have not constructed the required function. After all, what do you think Halt(D,D) should output?&lt;br /&gt;&lt;br /&gt;Therefore we have proven that it is always possible to construct a program which will cause Halt to give a wrong output. Similarly, you cannot construct an algorithm which will tell you if a particular action will be carried out in a program given an input because you can construct a program similar to D which will cause it to give the wrong output. Namely D(p) = if ActionPerfomed(p,p) then avoid_action else perform_action.&lt;br /&gt;&lt;br /&gt;QED&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-3467428494499137221?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/3467428494499137221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/cool-proofs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/3467428494499137221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/3467428494499137221'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/cool-proofs.html' title='Cool proofs'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-1382288241780242787</id><published>2010-07-27T14:55:00.000+02:00</published><updated>2010-07-28T15:06:18.730+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Typocalypse</title><content type='html'>Lately me and my friend Andreas Grech (&lt;a href="http://blog.dreasgrech.com/2010/07/typocalypse-typing-game-in-xna.html"&gt;http://blog.dreasgrech.com/&lt;/a&gt;) developed jointly a Microsoft XNA game in just under a sleepless and coffee ridden 24 hours called Typocalypse which is a game where you have to type the words under zombies before they reach you.&lt;br /&gt;&lt;br /&gt;My involvement in the game was in using my previous two blog posts, the biasing function for gradually increasing the difficulty of the game by gradually biasing the randomly chosen words to prefer longer words as the score increases and the trie for determining which zombies have a word which has a prefix that matches the currently typed text. I was also responsible for handling keyboard events, displaying the words under the zombies and sound effects which I created orally.&lt;br /&gt;&lt;br /&gt;To give credit where credit is due, the background music was taken from the Amiga game &lt;a href="http://en.wikipedia.org/wiki/The_Great_Giana_Sisters"&gt;The Great Giana Sisters&lt;/a&gt;, the pictures including the background image where found from google images and we couldn't be bothered with looking for them again and the library which enabled capturing of keyboard input was taken from &lt;a href="http://www.codeproject.com/KB/cs/globalhook.aspx"&gt;here&lt;/a&gt; which was developed by &lt;a href="http://geekswithblogs.net/gmamaladze/Default.aspx"&gt;George Mamaladze&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The game is open source and you can download and use the source code if you wish, but keep in mind that this was developed in under 24 sleepless hours so at some point coding started getting messy.&lt;br /&gt;&lt;br /&gt;Link to the game is &lt;a href="http://code.google.com/p/typocalypse/downloads/list"&gt;http://code.google.com/p/typocalypse/downloads/list&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Enjoy :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-1382288241780242787?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/1382288241780242787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/typocalypse.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/1382288241780242787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/1382288241780242787'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/typocalypse.html' title='Typocalypse'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-8548006973864106892</id><published>2010-07-21T01:54:00.001+02:00</published><updated>2011-09-22T14:01:37.857+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data structures'/><category scheme='http://www.blogger.com/atom/ns#' term='library'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='trie'/><title type='text'>C# Trie</title><content type='html'>In a recent project I have ventured into, I had to develop a set of classes in C# for a simple trie which are now released as open source (&lt;a href="http://code.google.com/p/typocalypse/source/browse/#hg/Trie"&gt;http://code.google.com/p/typocalypse/source/browse/#hg/Trie&lt;/a&gt;). This blog post shall describe how it works and how to use it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 180%;"&gt;Introduction to tries&lt;/span&gt;&lt;br /&gt;Simple tries are a data structure for mapping strings to values such that it enables you to efficiently retrieve all the values whose key strings have a particular prefix. This works by storing all the strings in a tree where each node is a prefix to a number of strings and each edge is a character to append to the prefix in the parent node. The root node is the empty string which is a prefix to all strings.&lt;br /&gt;&lt;br /&gt;As you traverse a path from the root downwards, you follow the edges which lead to prefixes of the string you are trying to match. Eventually if such a string exists, a node will be pointing to the value mapped by the string. By traversing the descendants of a particular node, you can retrieve all the stored strings which have that prefix in common and their corresponding value.&lt;br /&gt;&lt;br /&gt;Here's a diagram example from wikipedia:&lt;br /&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/b/be/Trie_example.svg"&gt;http://upload.wikimedia.org/wikipedia/commons/b/be/Trie_example.svg&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 180%;"&gt;Implemented trie&lt;/span&gt;&lt;br /&gt;The implemented trie supports adding, removing and character-by-character prefix searching of string-value pairs.&lt;br /&gt;&lt;br /&gt;The way it works is by keeping a reference in each node to a value object such that if the reference is null then the node does not point to a value object and hence the prefix is not a complete string. The type of the values is generic, any referencable type is allowed. Each node points to its children via a Dictionary object which maps characters to nodes, thereby allowing a fast search by following the characters.&lt;br /&gt;&lt;br /&gt;The following is a description of each class:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;TrieNode&lt;/span&gt;&lt;br /&gt;This is a non-public class which represents the nodes of the trie, that is, the prefixes. However in this implementation, the prefix itself is not stored, only the last character of the prefix called the Key is stored in order to know which character was followed to access this node. It also stores the value (generic type), a pointer to the parent node and a dictionary which maps characters to children nodes. If this node terminates a string then it's value field points to an object, otherwise it is null.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;PrefixMatcher&lt;/span&gt;&lt;br /&gt;This is a non-public class which is dedicated to allow the user to search the trie for a particular string or strings with a particular prefix. It was designed for enabling the user to search for the values of said strings on a character by character basis rather than providing the whole string immediately so that it can be used to search for user input as the user types in the query. This requires the maintenance of a state so that it is known which prefix has been entered thus far as well as which node that prefix is found in so as to enable an efficient search. For this reason the search feature was kept in a class of its own. Each time the trie is modified with the removal of a string, the current search is cancelled and must be redone from first character so as to avoid the user from searching non-existent strings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;IPrefixMatcher&lt;/span&gt;&lt;br /&gt;This is a public interface which abstracts the methods of the PrefixMatcher class so that the user is provided with an abstraction rather than a concrete class in order to search.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;Trie&lt;/span&gt;&lt;br /&gt;This is the main class which provides the features of the trie data structure. Searching is done through the public property "Matcher" which returns an instance of IPrefixMatcher. When a string is removed, the current search is cleared so as to avoid the user from searching non-existent strings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 180%;"&gt;Examples&lt;/span&gt;&lt;br /&gt;Here is an example of how to use the implemented trie:&lt;br /&gt;&lt;pre class="brush: c-sharp"&gt;&lt;br /&gt;            //Create trie&lt;br /&gt;            Trie &amp;lt; string &amp;gt; trie = new Trie &amp;lt; string &amp;gt; ();&lt;br /&gt;&lt;br /&gt;            //Add some key-value pairs to the trie&lt;br /&gt;            trie.Put("James", "112");&lt;br /&gt;            trie.Put("Jake", "222");&lt;br /&gt;            trie.Put("Fred", "326");&lt;br /&gt;&lt;br /&gt;            //Search the trie&lt;br /&gt;            trie.Matcher.NextMatch('J'); //Prefix thus far: "J"&lt;br /&gt;            trie.Matcher.GetPrefixMatches(); //[112, 222]&lt;br /&gt;            trie.Matcher.IsExactMatch(); //false&lt;br /&gt;            trie.Matcher.NextMatch('a');&lt;br /&gt;            trie.Matcher.NextMatch('m'); //Prefix thus far: "Jam"&lt;br /&gt;            trie.Matcher.GetPrefixMatches(); //[112]&lt;br /&gt;            trie.Matcher.NextMatch('e');&lt;br /&gt;            trie.Matcher.NextMatch('s'); //Prefix thus far: "James"&lt;br /&gt;            trie.Matcher.IsExactMatch(); //true&lt;br /&gt;            trie.Matcher.GetExactMatch(); //[112]&lt;br /&gt;&lt;br /&gt;            //Remove a string-value pair&lt;br /&gt;            trie.Remove("James");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 180%;"&gt;Link to classes&lt;/span&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/typocalypse/source/browse/#hg/Trie"&gt;http://code.google.com/p/typocalypse/source/browse/#hg/Trie&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-8548006973864106892?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/8548006973864106892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/c-trie.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/8548006973864106892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/8548006973864106892'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/c-trie.html' title='C# Trie'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4318944459823143473.post-1016285630707495606</id><published>2010-07-07T12:27:00.000+02:00</published><updated>2010-08-07T10:36:53.584+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maths'/><title type='text'>Biasing uniform random fraction generators towards larger or smaller fractions</title><content type='html'>The need for a function which allows you to bias a uniform probability distribution random number generator towards fractions closer to 0.0 or 1.0, and to control the degree of the bias, has been felt a few times whilst I was programming. C# only has uniform random number generators and in a recent project I had, I had to devise a function to enable me to bias the random numbers generated. In this post I shall describe this function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Problem&lt;/span&gt;&lt;br /&gt;We would like a function which skews the number line between 0.0 and 1.0 such that the range of numbers closer to 0.0 are denser than those closer to 1.0 or vice versa.&lt;br /&gt;&lt;br /&gt;Consider the following statistics gathered from the Python function random.random(), where we shall count the number of random numbers generated that are greater than 0.5 and those that are less out of 10000:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Seed&lt;/th&gt;&lt;th&gt;random()&amp;lt;0.5&lt;/th&gt;&lt;th&gt;random()&amp;gt;=0.5&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;4980&lt;/td&gt;&lt;td&gt;5020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;5023&lt;/td&gt;&lt;td&gt;4977&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;5038&lt;/td&gt;&lt;td&gt;4962&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The frequencies are very close to each other. This is because random.random() uses a uniform probability distribution, meaning that each number between 0.0 and 1.0 has an equal chance of being generated. But what if we wanted to bias the frequencies so that more numbers are less than 0.5?&lt;br /&gt;&lt;br /&gt;An application for this could be to randomly select an element from an array which is sorted on priority such that you want to randomly select the first element more often than the last. To do this you bias the random number generator towards smaller indices.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Solution&lt;/span&gt;&lt;br /&gt;We need a function which takes the set of inputs from 0.0 to 1.0 and returns numbers in the same range, however skewing the mapping such that a larger part of the number range gets mapped to a smaller part of the output range.&lt;br /&gt;&lt;br /&gt;In the graph below, &lt;span style="font-style: italic;"&gt;y = x&lt;/span&gt;, the mapping is unbiased, no part of the output range has been squashed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_BBrmXY05Ww8/TDTEx_3TYJI/AAAAAAAAAAk/oQ9_n1hDFDs/s1600/y%3Dx.png"&gt;&lt;img style="cursor: pointer; width: 318px; height: 320px;" src="http://1.bp.blogspot.com/_BBrmXY05Ww8/TDTEx_3TYJI/AAAAAAAAAAk/oQ9_n1hDFDs/s320/y%3Dx.png" alt="" id="BLOGGER_PHOTO_ID_5491230208907501714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However if we were to bend the line so that it still goes through (0,0) and (1,1) but is curved then we could skew the mapping as demonstrated below:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BBrmXY05Ww8/TDTFKIFbK9I/AAAAAAAAAAs/92AJXsPkXA0/s1600/y%3Df%28x,1%29.png"&gt;&lt;img style="cursor: pointer; width: 318px; height: 320px;" src="http://2.bp.blogspot.com/_BBrmXY05Ww8/TDTFKIFbK9I/AAAAAAAAAAs/92AJXsPkXA0/s320/y%3Df%28x,1%29.png" alt="" id="BLOGGER_PHOTO_ID_5491230623431076818" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BBrmXY05Ww8/TDTFWFqQlXI/AAAAAAAAAA0/Tipl6BRwJ08/s1600/y%3Df%28x,-1%29.png"&gt;&lt;img style="cursor: pointer; width: 318px; height: 320px;" src="http://3.bp.blogspot.com/_BBrmXY05Ww8/TDTFWFqQlXI/AAAAAAAAAA0/Tipl6BRwJ08/s320/y%3Df%28x,-1%29.png" alt="" id="BLOGGER_PHOTO_ID_5491230828938696050" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The graph on the left skews the output such that there is a bias for smaller numbers; all inputs which are less than 0.6 will be mapped to be closer to 0.0 whilst the rest of the inputs will be mapped to be closer to 1.0. On the other hand, the graph on the right skews the output such that there is a bias for larger numbers; only inputs smaller than 0.4 will be mapped to be closer to 0.0 whilst the rest of the inputs will be mapped to be closer to 1.0. Also, in the graph on the left, the smaller the number the greater the chance of it being returned whilst in the graph on the right, the larger the number the greater the chance of it being returned.&lt;br /&gt;&lt;br /&gt;We would like to devise a function which will give us this curve, and to some how parameterise the curvature so that the bias can be made stronger or weaker. Such a curve is given by the exponent function&lt;br /&gt;&lt;span style="font-style: italic;"&gt;y = x^k&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)&lt;br /&gt;which, given that k is positive, goes through (0,0) and (1,1) and which different values of k will change the curvature such that when k is between 0.0 and 1.0 the curvature will be going flatter and when k is between 1.0 and infinity the curvature will be going steeper.&lt;br /&gt;&lt;br /&gt;In order to control the curvature we shall allow the user to specify a point which the curve is to pass through. To find which value of k will go through the point (x',y'), we make k subject of the formula in (1) after substituting x with x' and y with y' and we get&lt;br /&gt;&lt;span style="font-style: italic;"&gt;k = ln y' / ln x'&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)&lt;br /&gt;and by substituting (2) into (1) we get&lt;br /&gt;&lt;span style="font-style: italic;"&gt;y = x^(ln y' / ln x')&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)&lt;br /&gt;which is useful for describing our curve, provided both y' and x' are between 0 and 1, both not included.&lt;br /&gt;&lt;br /&gt;However we would like the way we control the curvature to be more meaningful to the user. So instead we let the user provide just one variable, called the bias, which will be the x value which will be mapped to 0.5, hence all smaller values will be mapped to be less than 0.5 and all greater values will be mapped to be more than 0.5. To do this, we set y' to be 0.5, so that x' will be the bias, that is, the x value which gives 0.5. After modifying equation (3), the new equation is&lt;br /&gt;&lt;span style="font-style: italic;"&gt;y = x^(ln 0.5 / ln b)&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(4)&lt;br /&gt;where b is the bias.&lt;br /&gt;&lt;br /&gt;The following graphs are obtained for different values of b:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BBrmXY05Ww8/TDp18l6IKxI/AAAAAAAAABM/FCCsiOQnyGs/s1600/graphs.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 263px;" src="http://3.bp.blogspot.com/_BBrmXY05Ww8/TDp18l6IKxI/AAAAAAAAABM/FCCsiOQnyGs/s320/graphs.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5492832379360258834" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Results&lt;/span&gt;&lt;br /&gt;The following statistics demonstrate the validity of the function. Again 10000 random numbers are generated using Python's random.random() except that this time we shall pass the random numbers to the devised funtion as x using different values for b and all cases use a seed of 0:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;b&lt;/th&gt;&lt;th&gt;bias(random())&amp;lt;0.5&lt;/th&gt;&lt;th&gt;bias(random())&amp;gt;=0.5&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.1&lt;/td&gt;&lt;td&gt;1026&lt;/td&gt;&lt;td&gt;8974&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.5&lt;/td&gt;&lt;td&gt;4980&lt;/td&gt;&lt;td&gt;5020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.9&lt;/td&gt;&lt;td&gt;9043&lt;/td&gt;&lt;td&gt;957&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;So using this function we can easily give a bias to random number generators. The only problem with it is that a bias of zero or one will result in a log of zero and division by zero respectively and hence cannot be done.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Summary&lt;/span&gt;&lt;br /&gt;To bias a random number generator which gives random fractions so that it is biased towards numbers closer to 1 or 0, use the equation &lt;span style="font-style:italic;"&gt;y =  x^(ln 0.5 / ln b)&lt;/span&gt; where x is the unbiased random number, b is the fraction of numbers to be less than 0.5 and y is the biased random number.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4318944459823143473-1016285630707495606?l=geekyisawesome.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://geekyisawesome.blogspot.com/feeds/1016285630707495606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/biasing-uniform-random-fraction.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/1016285630707495606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4318944459823143473/posts/default/1016285630707495606'/><link rel='alternate' type='text/html' href='http://geekyisawesome.blogspot.com/2010/07/biasing-uniform-random-fraction.html' title='Biasing uniform random fraction generators towards larger or smaller fractions'/><author><name>mtanti</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BBrmXY05Ww8/TDTEx_3TYJI/AAAAAAAAAAk/oQ9_n1hDFDs/s72-c/y%3Dx.png' height='72' width='72'/><thr:total>5</thr:total></entry></feed>
