The Secret History of Codes & Code-breaking.
Simon Singh takes us on a journey through ages: from the cipher of Mary Queen of Scots, through Enigma, public key cryptography to quantum cryptography. He reveals the history of code making and code breaking.
The Code Book is not just about history. It is a study guide, too. Everything is illustrated with examples, formulas, and diagrams. Simon has a gift of describing frequency analysis, one way functions and even quantum computing in an simple way.
The Code Book is a great read. Highly recommended.
......................................
There is one thing in The Code Book, which may be interpreted as a proof that we live a computer simulation. It is about Thomas Young's experiment with a light source, a partition with two slits, and a screen. That experiment shows the wave nature of light. Waves of light reinforce or cancel each other producing multiple stripes on the screen. But nowadays we can send just one photon, wait for a minute, then send another, again wait, send another and so on. In this case, should we see multiple stripes on the screen or just two? Each photon that we send has no other photon to interact with, so it should behave like a particle and just go through one of the two slits. There should be only two stripes on the screen.
Simon writes: "However, for some extraordinary reason, even with single photons the result on the screen is still a pattern of light and dark stripes, just as if photons had been interacting." There are two scientific theories currently that try to explain it: superposition and multiverse. Either the photon passes through both slits simultaneously and then interacts with itself - that's superposition, or the universe splits into two which interfere with each other - that's multiverse.
Well, I'm a programmer, and from my point of view it looks like a silly bug. If I was designing the universe, I could easily make an error of assuming that the characters in my world would never get smart enough to send a single photon, so I would take a shortcut and compute the pattern as if photons were sent continuously. It's a simpler explanation than superposition or multiverse, isn't it? :-)
I need to learn more about photons.
Sunday, October 16, 2011
Tuesday, October 4, 2011
Washington, DC
Originally posted 2010-04-18.
During this spring break we went on a trip to Washington, DC. After a long winter the flora was eager to flourish again. A thick layer of pollen was obstructing visibility and making life difficult for people with allergies all the way from Florida to DC.
In South Carolina we saw this fine specimen of Luna Moth.
Here is one of them, the well known classical Capitol building.
The most famous museums in Washington belong to the Smithsonian Institution, and the most famous of them is the Air and Space, which takes pride in the quality of their artifacts: it showcases only originals in perfect condition. The admittance is free and the guided tours are excellent. Here are some examples of what is on display.
A nose section of Boeing 747.
The Enterprise orbiter. Smithsonian will get a real space shuttle after they are retired by NASA, if it can find the 20 something million dollar fee NASA wants for shipping and handling.
The retired British-French supersonic passenger jet - the Concorde.
Do you know why the windows are so tiny? It's because Concorde was flying much higher than other passenger jets, and if it lost a regular sized window, it would not be able to descend to safe height before suffocating everybody on board.
Enola Gay is the name of a B-29 plane that dropped an atomic bomb on Hiroshima. This specimen, like all others at Smithsonian, is an original.
The underside of a Predator UAV.
Finally, the UAVs. Boeing X-45 was an experimental Unmanned Aerial Vehicle. UAVs are the future of military aircrafts.
Our volunteer guide, a retired pilot, said that the F-35s are probably the last manned fighters the U.S. will produce.
Some less known museums and attractions.
Botanical Gardens near the Capitol.
The Building Museum was originally a home to the U.S. Pension Bureau headquarters.
Imagine that floor with a fountain in the middle, and plenty of air and natural light filled with desks.
This is what I call a decent office space.
The Basilica of the National Shrine of the Immaculate Conception - the largest Roman Catholic church in North America.
Ghostly Korean War Memorial.
The Postal Museum located near the Union Station is new and surprisingly interesting. You can learn that parts of U.S. Route 1 were originally a trail used by native Americans, and later by mail riders. You can learn that pneumatic mail delivery systems were operating in major U.S. cities in the XIX century.
U.S. Mail travelled under the seat of the driver of that stagecoach.
An ingenious postal snow mobile.
On the way back to Florida, we stopped again in South Carolina and visited Patriots Point Naval and Maritime Museum near Charleston.
Slowly deteriorating USS Yorktown aircraft carrier at Patriot's Point in South Carolina.
The legend for the stats.
International maritime signal flags.
Most planes on USS Yorktown are displayed with their wings folded allowing us to peek into the folding mechanism.
Japan - Tokyo, Yokohama - First Impressions
Originally posted 2008-03-22.
First impressions:
Long lines for passport control for foreigners at Narita Airport. I have waited for about 45 minutes. After the passport control everything went much smoother:
It was easy to use a public phone.
It was easy to buy a bus ticket.
On the bus journey to Tokyo my main impression was that Tokyo was more similar to European cities and thus more familiar to me than most of the U.S. cities I have seen:
The sidewalks made from pavers and actually used by people to walk.
The maximum use of space.
The trees planted in the sidewalks despite their narrowness.
The Carrefour and IKEA shops.
The buses and the trains.
The metric system: standard road signs in kilometers, temperature in degrees Celsius.
Small things.
The east entrance to the Imperial Gardens in Tokyo. The Imperial Palace is not visible from any point. The emperor does not wish to be disturbed.
Shin-Yokohama means new Yokohama. The Shinkansen stops at Shin-Yokohama. Tokyo Central is only two stops away.
This is a picture of one of the 3 types of Shinkansen trains operated by JR Tokai. I love these trains: fast, quiet, safe, comfortable.
The view of Tokyo from the Tokyo Tower.
Monday, October 3, 2011
Exile
Originally posted 2008-04-17.
Author: Richard North Patterson
Category: Fiction
Ready by: Dennis Boutsikaris
CDs: 17
A very objective look at the Israeli-Palestinian conflict. You will listen to many disturbing stories. You will hear from people living in that divided strip of land, talking about their rationales for living there, occupation, suicide bombings, hatred of others. Few will talk about their hopes for life in peace.
The author, Richard North Patterson prepared very well. He visited Israel and Palestine. He talked to influential people.
The fictional story is about David Wolfe and Hana Arif. He is a US citizen and a Jew. She is a Palestinian. They studied together law at Harward, but their ways parted afterwards. They meet again after 13 years and that's all I can say without giving up the plot.
The book is very captivating, especially towards the end. I did not mind traffic jams at all while listening to the story.
The narrator, Dennis Boutsikaris is very skilled allowing you to immerse in the story and almost forget that all voices come from the same person. Female voices sound a bit harsh, but maybe it was intentional.
Author: Richard North Patterson
Category: Fiction
Ready by: Dennis Boutsikaris
CDs: 17
A very objective look at the Israeli-Palestinian conflict. You will listen to many disturbing stories. You will hear from people living in that divided strip of land, talking about their rationales for living there, occupation, suicide bombings, hatred of others. Few will talk about their hopes for life in peace.
The author, Richard North Patterson prepared very well. He visited Israel and Palestine. He talked to influential people.
The fictional story is about David Wolfe and Hana Arif. He is a US citizen and a Jew. She is a Palestinian. They studied together law at Harward, but their ways parted afterwards. They meet again after 13 years and that's all I can say without giving up the plot.
The book is very captivating, especially towards the end. I did not mind traffic jams at all while listening to the story.
The narrator, Dennis Boutsikaris is very skilled allowing you to immerse in the story and almost forget that all voices come from the same person. Female voices sound a bit harsh, but maybe it was intentional.
Danny Deckchair
Originally posted 2009-12-20.
Category: Romantic Comedy
Actors: Rhys Ifans, Miranda Otto, Justine Clarke
Screenplay: Jeff Balsmeyer
Director: Jeff Balsmeyer
Year: 2003
Running Time: 1 hour 40 minutes
Rhys Ifans plays Danny Morgan, a cement man in Sydney who desparately needs his vacation. Unfortunately, his partner Trudy Dunphy, played by Justine Clarke, does not share his love for rustic camping. She would rather stay in the city and pursue her career and a more important man.
Danny Deckchair is a refreshingly light, intriguing, story of finding one's place and mate. Highly recommended, especially when feeling down.
The PG-13 rating in the U.S. is nuts. This is a PG movie.
Category: Romantic Comedy
Actors: Rhys Ifans, Miranda Otto, Justine Clarke
Screenplay: Jeff Balsmeyer
Director: Jeff Balsmeyer
Year: 2003
Running Time: 1 hour 40 minutes
Rhys Ifans plays Danny Morgan, a cement man in Sydney who desparately needs his vacation. Unfortunately, his partner Trudy Dunphy, played by Justine Clarke, does not share his love for rustic camping. She would rather stay in the city and pursue her career and a more important man.
Danny Deckchair is a refreshingly light, intriguing, story of finding one's place and mate. Highly recommended, especially when feeling down.
The PG-13 rating in the U.S. is nuts. This is a PG movie.
Clockwise
Originally posted 2008-04-19.
Category: Comedy
Actors: John Cleese
Screenplay: Michael Frayn
Year: 1986
Running Time: 1 hour 36 minutes
John Cleese plays Brian Stimpson - a headmaster obsessed with punctuality. His school resembles a workcamp with principal Stimpson keeping an eye on everyone from his watch-tower.
His few vices include not paying attention to what people say and overusing the word "right", right?
This light comedy is a pleasure to watch. Not overdone. Not boring. Not irritating. Just right.
Category: Comedy
Actors: John Cleese
Screenplay: Michael Frayn
Year: 1986
Running Time: 1 hour 36 minutes
John Cleese plays Brian Stimpson - a headmaster obsessed with punctuality. His school resembles a workcamp with principal Stimpson keeping an eye on everyone from his watch-tower.
His few vices include not paying attention to what people say and overusing the word "right", right?
This light comedy is a pleasure to watch. Not overdone. Not boring. Not irritating. Just right.
Playing for Pizza
Originally posted 2008-06-18.
Author: John Grisham
Category: Fiction
Read By: Christopher Evan Welch
I do not know much about American football, but the story of an extremely unlucky NFL player Rick Dockery is still captivating.
Playing for Cleveland Browns, Rick makes 3 mistakes in a matter of minutes, and lands unconscious in a hospital. He's fired. Browns fans want to kill him...
John Grisham likes Italy. This is his second book I listened to, that takes place mostly in Italy. He likes the food, the people, the clothes, the way of life. I like it too. It is hard not to.
Predictably Irrational - The Hidden Forces That Shape Our Decisions
Originally posted 2010-03-07.
Author: Dan Ariely
Category: Popular Science
Read By: Simon Jones
CDs: 6
Refreshing, if not groundbreaking, look at human behavior in the context of economics.
Dan Ariely writes about results of real, clever and meaningful research experiments in a very approachable way.
Even though this is a truly scientific book, it has very practical implications for regular consumers like you and me. Make sure you read it before making your next big purchase. An eye opener.
For all chapter overviews go to wikipedia: Predictably Irrational
Highly recommended for adults. Contains details of reasearch about human sexuality that may not be appropriate for young readers.
Huffman's compression algorithm implemented in JavaScript
Originally published 2009-06-02, on tom-ash.net
The other night I have implemented Huffman's compression algorithm in JavaScript. Here is a wiki link describing what Huffman coding is:
Huffman coding
Here is my JavaScript implementation:
The other night I have implemented Huffman's compression algorithm in JavaScript. Here is a wiki link describing what Huffman coding is:
Huffman coding
Here is my JavaScript implementation:
<html> <head> <title>Huffman's compression algorithm implemented in JavaScript
by Tomasz Andraszek</title>
<script type="text/javascript"> function compress() { var input = document.getElementById("input").value; document.getElementById("inputlength").innerHTML =input.length*8; var probabilities = getProbabilities(input); var codes = getCodes(probabilities); var output = compressHuffman(input, codes); var temp = ""; for (var elem in probabilities) { temp += elem + " = " + probabilities[elem] + "<br/>"; } document.getElementById("probabilities").innerHTML = temp; temp = ""; for (var elem in codes) { temp += elem + " = " + codes[elem] + "<br/>"; } document.getElementById("codes").innerHTML = temp; document.getElementById("output").innerHTML = output; document.getElementById("outputlength").innerHTML =output.length; } function sortNumberAsc(a, b) { return a[1] - b[1]; } function getCodes(prob) { var tree = new Array(); var secondTree = new Array(); this.getNext = function() { if (tree.length > 0 && secondTree.length > 0 && tree[0].prob < secondTree[0].prob) return tree.shift(); if (tree.length > 0 && secondTree.length > 0 && tree[0].prob > secondTree[0].prob) return secondTree.shift(); if (tree.length > 0) return tree.shift(); return secondTree.shift(); } var sortedProb = new Array(); var codes = new Array(); var x = 0; for (var elem in prob) { sortedProb[x] = new Array(elem, prob[elem]); x = x + 1; } sortedProb = sortedProb.sort(sortNumberAsc); x = 0; for (var elem in sortedProb) { tree[x] = new node(); tree[x].prob = sortedProb[elem][1]; tree[x].value = sortedProb[elem][0]; x = x + 1; } while (tree.length + secondTree.length > 1) { var left = getNext(); var right = getNext(); var newnode = new node(); newnode.left = left; newnode.right = right; newnode.prob = left.prob + right.prob; newnode.left.parent = newnode; newnode.right.parent = newnode; secondTree.push(newnode); } var currentnode = secondTree[0]; var code = ""; while (currentnode) { if (currentnode.value) { codes[currentnode.value] = code; code = code.substr(0, code.length - 1); currentnode.visited = true; currentnode = currentnode.parent; } else if (!currentnode.left.visited) { currentnode = currentnode.left; code += "0"; } else if (!currentnode.right.visited) { currentnode = currentnode.right; code += "1"; } else { currentnode.visited = true; currentnode = currentnode.parent; code = code.substr(0, code.length - 1); } } return codes; } function node() { this.left = null; this.right = null; this.prob = null; this.value = null; this.code = ""; this.parent = null; this.visited = false; } function compressHuffman(input, codes) { var output = input.split(""); for (var elem in output) { output[elem] = codes[output[elem]]; } return output.join(""); } function getProbabilities(input) { var prob = new Array(); var x = 0; var len = input.length; while (x < len) { var chr = input.charAt(x); if (prob[chr]) { prob[chr] = prob[chr] + 1; } else { prob[chr] = 1; } x++; } for (var elem in prob) { prob[elem] = prob[elem] / len; } return prob; } </script> </head> <body> Type in the text to compress here:<br /> <textarea id="input" rows="5" cols="80">aaabcc</textarea><br/> <input type="button" onclick="compress()" value="Compress" /><br/> Text's length (8 bits per character): <span id="inputlength"></span><br/> Probabilities of all distinct characters in the text:<br />
<span id="probabilities"></span><br/> Binary codes assigned to characters: <br /><span id="codes"></span><br/> Binary output: <span id="output"></span><br/> Output's length in bits: <span id="outputlength"></span><br/> </body> </html>
Enums in JavaScript
Originally published 2008-12-27, on tom-ash.net
JavaScript does not support enums like these in C#:
The simplest way to get enum functionality in JavaScript is to create a variable using JSON:
JavaScript does not support enums like these in C#:
enum SpriteSize { Small = 100, Big = 200 } void Render(SpriteSize spriteSize) { if (spriteSize == SpriteSize.Small) { // TODO: implement } }
The simplest way to get enum functionality in JavaScript is to create a variable using JSON:
<script type="text/javascript"> var SpriteSize = { Small: 100, Big: 200 } function Render(spriteSize) { if (spriteSize == SpriteSize.Small) { // TODO: implement } } </script>
Hunting Deadlocks - SQL Server 2000
One of a series of posts from andraszek.net posted originally between 2006 and 2010.
A typical scenario for a deadlock is described in Books Online: two procedures which try to use two tables in a different order, block each other after aquiring a lock to the first table.
I will describe here a different scenario: one procedure using one table. How can a deadlock occurr in such a case? Let's see.
It all starts with SQL Error 1205: Your transaction (process ID #99) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun your transaction.
First, let's enable SQL Server Trace 1204 flag. You must be in sysadmin server role to execute the following statement:
The trace, by default is written to this file:
C:\Program Files\Microsoft SQL Server\MSSQL\LOG\ERRORLOG
Here we find details of our deadlock:
You can notice that both nodes executed procedure InvoiceUpdate. From the KEY you can decipher the object they fought for:
10 is database id,
1266375687 is table id,
and 1 or 3 are index ids.
Find name of the database:
Find name of the table:
This may be a temporary object, for example a cursor, which will not exist when we check later. In this case find name of the table from the stored procedure: just look for line # provided by trace.
There is a little trap here: if your procedure calls another procedure, then the deadlock may actually occurr in the subprocedure and the line number applies to the subprocedure.
Find ids and names of the indexes:
Find keys of the indexes:
Both instances aquire a shared lock to a range of rows, and then one of them tries to escalate that lock to exclusive to update a row, but cannot, because the other keeps it and also tries to escalate to exclusive to update another row.
The problem is that the initial shared lock was too wide. The index used was not optimal for the SELECT statement and too many rows were locked.
The solution is to create another index which matches exactly the WHERE clause used in the SELECT. This of course does not solve the problem if there are two or more processes that try to execute this procedure with the same parameters. The application has to be designed in a way that processes operate on different sets of data.
A typical scenario for a deadlock is described in Books Online: two procedures which try to use two tables in a different order, block each other after aquiring a lock to the first table.
I will describe here a different scenario: one procedure using one table. How can a deadlock occurr in such a case? Let's see.
It all starts with SQL Error 1205: Your transaction (process ID #99) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun your transaction.
First, let's enable SQL Server Trace 1204 flag. You must be in sysadmin server role to execute the following statement:
DBCC TRACEON (1204)
The trace, by default is written to this file:
C:\Program Files\Microsoft SQL Server\MSSQL\LOG\ERRORLOG
Here we find details of our deadlock:
Deadlock encountered .... Printing deadlock information 2004-10-15 19:14:04.64 spid4 2004-10-15 19:14:04.64 spid4 Wait-for graph 2004-10-15 19:14:04.64 spid4 2004-10-15 19:14:04.64 spid4 Node:1 2004-10-15 19:14:04.64 spid4 KEY: 10:1266375687:3 (dd0025eb9a53) CleanCnt:1 Mode: S Flags: 0x0 2004-10-15 19:14:04.64 spid4 Grant List 1:: 2004-10-15 19:14:04.64 spid4 Owner:0x655ac660 Mode: S Flg:0x0 Ref:1 Life:00000000 SPID:75 ECID:0 2004-10-15 19:14:04.64 spid4 SPID: 75 ECID: 0 Statement Type: SELECT Line #: 29 2004-10-15 19:14:04.64 spid4 Input Buf: RPC Event: InvoiceUpdate;1 2004-10-15 19:14:04.64 spid4 Requested By: 2004-10-15 19:14:04.64 spid4 ResType:LockOwner Stype:'OR' Mode: X SPID:64 ECID:0 Ec:(0x63B3F580) Value:0x57648ee0 Cost:(0/3C) 2004-10-15 19:14:04.64 spid4 2004-10-15 19:14:04.64 spid4 Node:2 2004-10-15 19:14:04.64 spid4 KEY: 16:1153035489:1 (d1003ffe1113) CleanCnt:1 Mode: X Flags: 0x0 2004-10-15 19:14:04.64 spid4 Grant List 0:: 2004-10-15 19:14:04.64 spid4 Owner:0x42bc2140 Mode: X Flg:0x0 Ref:0 Life:02000000 SPID:64 ECID:0 2004-10-15 19:14:04.64 spid4 SPID: 64 ECID: 0 Statement Type: UPDATE Line #: 679 2004-10-15 19:14:04.64 spid4 Input Buf: RPC Event: InvoiceUpdate;1 2004-10-15 19:14:04.64 spid4 Requested By: 2004-10-15 19:14:04.64 spid4 ResType:LockOwner Stype:'OR' Mode: S SPID:75 ECID:0 Ec:(0x61D09580) Value:0x655ad200 Cost:(0/0) 2004-10-15 19:14:04.64 spid4 Victim Resource Owner: 2004-10-15 19:14:04.64 spid4 ResType:LockOwner Stype:'OR' Mode: S SPID:75 ECID:0 Ec:(0x61D09580) Value:0x655ad200 Cost:(0/0)
You can notice that both nodes executed procedure InvoiceUpdate. From the KEY you can decipher the object they fought for:
10 is database id,
1266375687 is table id,
and 1 or 3 are index ids.
Find name of the database:
SELECT [name] FROM master.dbo.sysdatabases WHERE dbid = 10
Find name of the table:
SELECT OBJECT_NAME('1266375687')
This may be a temporary object, for example a cursor, which will not exist when we check later. In this case find name of the table from the stored procedure: just look for line # provided by trace.
There is a little trap here: if your procedure calls another procedure, then the deadlock may actually occurr in the subprocedure and the line number applies to the subprocedure.
Find ids and names of the indexes:
SELECT indid, [name] FROM sysindexes WHERE id =
OBJECT_ID('Invoice')
Find keys of the indexes:
sp_helpindex 'Invoice'
Both instances aquire a shared lock to a range of rows, and then one of them tries to escalate that lock to exclusive to update a row, but cannot, because the other keeps it and also tries to escalate to exclusive to update another row.
The problem is that the initial shared lock was too wide. The index used was not optimal for the SELECT statement and too many rows were locked.
The solution is to create another index which matches exactly the WHERE clause used in the SELECT. This of course does not solve the problem if there are two or more processes that try to execute this procedure with the same parameters. The application has to be designed in a way that processes operate on different sets of data.
Static Methods and Their Variables - .NET 1.1
One of a series of posts from andraszek.net posted originally between 2006 and 2010.
Have you ever wondered about local variables of static methods? Are they static too? Or are they call-specific? What happens with the variables when a second thread calls the method while the first has not finished executing it yet? The code below allows examining this.
Here is the output:
Have you ever wondered about local variables of static methods? Are they static too? Or are they call-specific? What happens with the variables when a second thread calls the method while the first has not finished executing it yet? The code below allows examining this.
// You may need to run this C# .NET console application // a few times before you get interesting results // Have fun! using System; using System.Threading; namespace Andraszek.net { class StaticMethodExample { public static void ShowXTwice () { // Uncomment the line below to see what happens if only one thread at // a time is allowed to use type StaticMethodExample // Observe the average number of ticks go up //lock (typeof(StaticMethodExample)) { Random r = new Random(); // Although the ShowXTwice method is static, each thread has its own instance of x // otherwise, all threads would use the same variable // and as a result sometimes x would have a different value when checked for the // second time. // For example: x checked for the first time by thread 1 (x=123), then thread 2 // assigns a new value to x (x=456), and now thread 1 checks x for the second time // int x = r.Next(1, 10000); Console.WriteLine(Thread.CurrentThread.Name + " Checking x for the first time: " + x.ToString()); Console.WriteLine(Thread.CurrentThread.Name + " Checking x for the second time: " + x.ToString()); } } } class TestStaticMethodExample { public static void Main() { int maxThreads = 100; Thread[] threads = new Thread[maxThreads]; for (int i = 0; i < maxThreads; i++) { Thread t = new Thread( new ThreadStart(StaticMethodExample.ShowXTwice)); t.Name = "Thread " + i.ToString(); threads[i] = t; } long startTicks = DateTime.Now.Ticks; for (int i = 0; i < maxThreads; i++) { threads[i].Start(); } // wait for all threads to finish for (int i = 0; i < maxThreads; i++) { threads[i].Join(); } long endTicks = DateTime.Now.Ticks; Console.Write("Number of ticks from start to end: "); Console.WriteLine(endTicks - startTicks); Console.WriteLine("Press Enter"); Console.ReadLine(); } } }
Here is the output:
Unintuitive syntax - ABAP 4
One of a series of posts from andraszek.net posted originally between 2006 and 2010.
Here is an example of a twisted "colon and comma" logic from SAP ABAP 4 programming language:
This statement will update CITY for all rows and PHONE for the row with ID = '000899888'. The reasoning behind this is that by putting a colon we actually start defining statement chains: statements separated by commas. The whole thing ends with a full stop, which marks the end of every statement in ABAP 4.
This concept will be very weird to all SQL programmers.
Here is an example of a twisted "colon and comma" logic from SAP ABAP 4 programming language:
UPDATE contacts SET: CITY = 'WARSZAWA', PHONE = '+48 22 1234567' WHERE ID = '000899888'.
This statement will update CITY for all rows and PHONE for the row with ID = '000899888'. The reasoning behind this is that by putting a colon we actually start defining statement chains: statements separated by commas. The whole thing ends with a full stop, which marks the end of every statement in ABAP 4.
This concept will be very weird to all SQL programmers.
Custom SQL Server 2005 Aggregates
One of a series of posts from andraszek.net posted originally between 2006 and 2010.
Custom aggregates are as fast as built in T-SQL aggregates like MAX(), SUM(), etc..
Here is the C# source code for an aggregate that concatenates short strings:
And here it is in action:
Custom aggregates are as fast as built in T-SQL aggregates like MAX(), SUM(), etc..
Here is the C# source code for an aggregate that concatenates short strings:
using System; using System.Text; using System.IO; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; [Serializable] [SqlUserDefinedAggregate( Format.UserDefined, //use clr serialization to serialize the intermediate result IsInvariantToNulls = true, //optimizer property IsInvariantToDuplicates = false, //optimizer property IsInvariantToOrder = false, //optimizer property MaxByteSize = 8000) //maximum size in bytes of persisted value ] public struct Concatenate : IBinarySerialize { private StringBuilder _IntermediateResult; // 8000 - 2 control bytes - 4 bytes for 2 UTF-16 characters = 7994 private const int _MaxSize = 7994; public void Init() { _IntermediateResult = new StringBuilder(); } public void Accumulate(SqlString value) { if (!value.IsNull && (_IntermediateResult.Length + value.GetUnicodeBytes().Length < _MaxSize)) { _IntermediateResult.Append(value.Value).Append(", "); } } public void Merge(Concatenate group) { if ((_IntermediateResult.Length + group._IntermediateResult.Length) < _MaxSize) { _IntermediateResult.Append(group._IntermediateResult); } } public SqlString Terminate() { string output = String.Empty; // Delete the trailing comma and space, if any if (_IntermediateResult != null && _IntermediateResult.Length > 1) { output = _IntermediateResult.ToString(0, _IntermediateResult.Length - 2); } return new SqlString(output); } public void Read(BinaryReader reader) { _IntermediateResult = new StringBuilder(reader.ReadString()); } public void Write(BinaryWriter writer) { writer.Write(_IntermediateResult.ToString()); } }
And here it is in action:
CREATE AGGREGATE Concatenate (@input nvarchar(4000)) RETURNS nvarchar(max) EXTERNAL NAME SqlClr.Concatenate GO SELECT Title, dbo.Concatenate(FirstName) AS [First Names] FROM Person.Contact GROUP BY Title Title First Names -------- --------------------------------------------- Sr. José, Jésus, Anibal, José, Luis, Gustavo, Ciro, Humberto, Alvaro, Adrian, Ramón Sra. Janeth, Pilar, Janaina Barreiro Gambaro [...]
The law is a poorly written program/application/system
Originally published 2005-12-08, on myspace.com.
It struck me today that the written law is very similar to a poorly written program.
All these "the aforementioned party" and "the other party" and "with the exception of article 9, 5 and 6", and the sentences half page long, and references to other papers cropped all over ...
Do you remember BASIC with the GOTO statement or the assembler language? Now obfuscate it: remove all comments from that code. Replace all subroutine names with numbers, put extra GOTOs, and voila: you have the tax code.
The difference is: the user of the BASIC code - someone who plays a computer game for example - cannot be put to jail for not knowing and understanding every line of the computer code. The tax code user - can.
There are hundreds of thousands of lines of tax code, and they, as a system, change all the time. Why on Earth, we - the users - are obliged to know, understand and keep track of that? Give it to machines instead of us, lawyers, and judges. Give it to the Common Language Runtime. Let it analyze all references. Let it break trying to compile it. Let it freeze before displaying a verdict...
Old web sites
About a month ago, I've cancelled my old 1and1 domains and web hosting. The following web sites are gone: andraszek.net, tom-ash.net, whilenotnull.net.
I will re-post some old material here.
I will re-post some old material here.