Download an executable jar file containing the Traveller release "epsilon" Java 1.4 source code, a makefile, the byte compiled classes, a copy of this document with accompanying screenshots, some licenses, and other documentation.

Traveller.jar

[I've completely given up trying to present Traveller here as an applet. Sorry about that. Applets don't work using standard mechanisms in my non-standard MS-Windows 98/Cygwin development environment, and I have no computer to test my web site over whose operation I have control. Writing software you cannot test properly is just a fast way to a bad reputation and a nervous breakdown. Those interested in running Traveller in their own Java runtime environment are still invited to download the jar file and enjoy themselves, where it starts out looking like this. [Screenshots for this document for the epsilon release of Traveller are from a "nested grid" layout, run a couple of times to show different features. The problem size is 337 cities, the population size is 40 members. This is Traveller's most difficult current layout pattern, much harder than random layouts because its fitness landscape is full of very deep local optima potholes, and so far I only know that it cannot be completely solved in 117,000+ seconds at the current state of Traveller's heuristics, though I ran out of patience with only two more fixes needed, easily determined by eye in this regular layout pattern.]


Traveller Splash Panel

One would think, as crucial as applet presentation is to the successful evangelizing of Java, that how to make Java applets run from browser windows would be as well documented and supported in Sun's documention as is the Java language API, but such is emphatically not the case. Grrrr.]

What is this Traveller applet?

Traveller is a Java language application which sets up and runs a choice of many genetic algorithm heuristics to solve a particular variety of the famous Traveling Salesman Problem, while letting the user have a lot of control over the algorithms used and the problem characteristics.

The spelling of the name "Traveller".

It is best to lay this controversial issue to rest at once. Scott Robert Ladd (henceforth "SRL" or "Scott") wrote the original of this demo as an applet for the ("Blind" version of the) Symmetrical Euclidean Traveling Salesman Problem, and he used an alternative spelling "Traveller", for which he has apparently received endless grief. He came back, on his spiffy Coyote Gulch web site (from which Traveller comes), to defend the spelling as an accepted alternative. Well, yes and no. You will find it in many dictionaries. It is an acceptable spelling under British rules (which earlier followed the current American rules), to double the "l", but the American rules double the consonant when adding a suffix, only when

Which latter is not the case for the word "travel". Nevertheless, it is Scott's original work, and Scott's choice, so until he changes his mind, the spelling stays as Scott and the British do it, and it is we Yanks who will have to show the stiff upper lip in these trying times. Besides, the spelling is now so embedded in the existing code class names and such, it would be a chore to rip it out at this point, and then the British would just declare war in retaliation for the insult to their orthography, and... .

What is the status of the Traveller source code?

Scott's original code was published under the GNU Public License, or GPL. My additions and modifications are freeware, since I'm not into legalisms. Under the Berne copyright convention, both Scott and I hold copyright on the code we separately wrote, automatically. [What the status is of the stuff mishmashed together I haven't a clue, best take the conservative approach and assume it is all GPLed.] My license of my copyright to you is that you may do whatever you want with my code, whether for commercial or private use, as long as you don't try to hold me responsible for the consequences. Credit to me as the author would be polite, but is not required. Scott's license to you is contained in the GPL; the most recent version of the GPL is available online from the Free Software Foundation, at

GNU Public License or by surface mail request from:
     Free Software Foundation, Inc.
     59 Temple Place - Suite 330
     Boston, MA 02111-1307, USA.

and also included in the files COPYING and COPYING.LIB (two considerably different licenses) in the Traveller.jar file.

For purposes of contacting me about my copyright (please don't), I am most recently living homeless at

     Kent Paul Dolan
     General Delivery
     Clovis, California, United States of America 93612-9999

but I am more usually known and reliably contacted since 1988 as xanthian@well.com or known as "xanthian", or since 1986 as "Kent, the man from xanth", but henceforth will be known here as "KPD".

Glossary

Traveller uses some unfamiliar words, and some familiar words in specialized ways. Here are the most important of them.

city
codon
node
vertex

The SETSP (see next section) involves travels through a set of Euclidean (x,y) coordinate pairs laid out on a two dimensional coordinate system. From the point of view of the human "traveling salesman" model, these are "cities". From the point of view of the graph which the cities and paths connecting them create, these are "nodes" or "vertices". From the point of view of a genetic algorithm, these smallest individual components of the genome are "codons". In particular, for Traveller, those codons contain a number which is the city's name.

chromosome
genome
tour

The aggregate of genetic information which a genetic algorithm manipulates in a single reproducing entity, and which its designer uses to describe the problem in term of its domain of discourse is precisely a "genome", or more colloquially a "chromosome". From the viewpoint of the human "traveling salesman" model, the Traveller genome encodes the salesman's "tour". This tour, and thus the genome, is independent of the description that starts with one particular one of its cities/nodes; it is like a ring, with no distinguished beginning or end, and this realization becomes important when implementing genetic algorithms.

edge
link
path

The connection by a straight line from one coordinate pair of a tour to the next is an "edge" from the point of view of the graph which the nodes define, occasionally a "link" or "path" from the point of view of the traveler and city model. What is important to Traveller and to the solution of the SETSP is the length of this link, and even more the sum of the lengths of all the links in the current tour, which sum is the genome's fitness.

What is the Symmetrical Euclidean Traveling Salesman Problem (SETSP), and why should I care?

Briefly but carefully expressed, the SETSP is this. In the two dimensional Cartesian coordinate system plane, with the usual Euclidean distance metric, and distances between coordinate pairs the same in both directions, given a set of coordinate pair locations, conceptually "cities", and an agent, conceptually "a traveler"; then, find for that traveler the closed circuit path that goes through each of those cities once and only once, and which has the shortest total length.

This problem is interesting for several reasons.

So just how hard is "very hard"?

I use 79 cities as my benchmark point, for sentimental reasons. I call it my "particle death of the universe"-sized problem (or my "the end of the matter"-sized problem).

My computer runs at a half-a-gigaHertz clock cycle, and, I think, does one floating-point operation per cycle. To evaluate the fitness of an SETSP tour ("genome") takes (at least) seven floating-point operations ("flops") per city.

My computer is made of matter, largely consisting of protons. All the protons in the universe are expected to have disintegrated in 10^100 years (That's a 1 with 100 zeros after it). The universe is currently about 15,000,000,000 years old, a submicroscopic beginning on such a time-span.

The brute force exhaustive search approach to solving the SETSP is to form every possible permutation of the cities (in no particular order of creating the permutations so that no fitness evaluation shortcuts are available), evaluate the path length ("fitness") for each permutation, and select the one with the shortest path length ("best fitness").

In attempting to solve a 79 city problem by the brute force exhaustive search approach, my computer, sadly, would fail, as it would see all its protons disintegrate first. Solving that problem at the speed of my computer would require just under 9*10^101 years, or just 90 times longer than it will take the last proton in the universe to disintegrate.

Maybe a bigger computer would help? [Excuse me if I drop a digit or two answering, the last time I read the needed numbers was a very long time ago.] Well, if all the matter in the entire universe, around 10^70 protons and neutrons, were turned into computers like my computer, it would be sufficient to make about 10^46 of them. If a 79 city SETSP problem instance were partitioned evenly among them and a massively parallel brute force solution attempted, granted not all the protons would have disintegrated after 10^56 years, but probably all interest in the problem solution would have disintegrated by then.

So, perhaps the brute force approach is not the best choice.

My best approach to solving the SETSP so far, finds the exact solution for a 79 city case, occasionally in as little as 40 minutes, though more often in a couple of hours, using a mix of genetic algorithms and good approximate solution initial seed genomes. [ UPDATE: as of 2002/03/25, Traveller solves 80 cities with a population of 80 members and "best practice" settings (on an even grid, so I know the right answer) in 61 seconds including setup time. Looks like I'm making progress.]

Paid professionals, using gangs of computers working in concert, and much more sophisticated algorithms, have exactly solved problems of around 15,000 cities in under a year, as their current "high water mark". Literally cities, in this case, they were working from a modern German map.

The problems of similar complexity to the SETSP, prevalent in integrated circuit design, feature millions of way-points, and are not exactly solvable in general in commercially useful times by any known algorithm. Simulated annealing is the heuristic algorithm of choice, last I read (and works well enough that we now have computers that sit on our laps and run half a gigaHertz).

What is the Blind Traveling Salesman Problem, and why did Scott choose it?

The traveling salesman (or here, the algorithm which represents that salesman) is blind when the only information available to the genetic algorithm part of the code for use about the path lengths is the total length of the circuit, not any of the city to city distances that make up that circuit.

This version of the problem is particularly suitable for genetic algorithm approaches, which insist on a single fitness metric. Also, it removes the complexity of various algorithms that attempt to improve performance by taking advantage of more local information.

Unlike the purity of Scott's version, mine makes available many "sighted cheats", to be turned on at the user's option. Providing good starting seed genomes, as with the minimal spanning tree seeds, is obviously one such cheat. All of my permutation algorithms are technically cheats because they save work by not calculating the full circuit fitness, but they could in concept just as easily compute and work with the full fitness, so their approach isn't as big a cheat. The "optimize near a point" group of heuristics are completely sighted cheats, they take advantage of knowing city locations to pick the cities nearest a point in the play-field to try to optimize some characteristic of the tour near just those few cities (they should be as awesome as they seem, too; they is certainly complicated enough compared to the lean beauty of Scott's Cyclic Crossover, say). Similarly, when implemented, local optimization seeds, probably from 2-OPT or 3-OPT (whatever those are) approaches, when I can steal some working code, or a greedy algorithm, when I feel like bothering to code one, or that spiffy relaxation of an ellipse to a solution I've seen several places on the Net, [done, see "Elastic Net" below] would all be sighted cheats providing good seeds.

So why does Traveller use a genetic algorithm instead of doing a direct solution?

Because no one in all that research time has ever found a polynomial time direct solution, and it is quite possible that no such direct solution even exists.

Where no direct solution algorithm exists, but the problem needs solving anyway, computer programmers and other researchers and practitioners employ heuristics, methods that seem to work well most of the time but cannot be proved to work all of the time, and sometimes don't. Every computer weather forecast you've ever seen was done with a heuristic, for example. No direct computational solution to the weather forecasting problem in feasible time is known to exist. The less understood the problem domain is, the chancier use of heuristics becomes, thus hurricanes arrive unexpectedly at your picnics.

However, the programming concept of genetic algorithms is that they help us find solutions, quickly anyway, for which no fast, direct solution is known, and where we don't very well understand the problem domain. Genetic algorithms are often used for problems whose solution is not well understood, and they often perform very well, in commercially successful ways. However, genetic algorithms themselves are not very well understood. Understanding them better is one of the goals of Traveller.

What a genetic algorithm does is to imitate that highly successful technique seen in nature, evolution by natural selection. Because computer algorithms' generations can run so much faster than the generation times of nature, this very inefficient process that takes millions of years in nature to create a higher brow line, finds solutions much more quickly in a computer. Typically genetic algorithms employ these parts.

The purposes of the SRL version of the applet Traveller.

Scott wrote Traveller as code to be part of a textbook. It is meant to be of a tutorial nature, efficient in the small with fast generation times, but not blindingly fast to find a solution, not industrial strength, not meant for huge problem sizes, and not the perfect algorithm (no one has found one, and if one existed, it would probably be too complicated for use in a textbook). Keep this in mind when trying to evaluate Scott's version of Traveller.

[After my hack, slash, and burn attacks changing his code, Traveller still doesn't have any of those features, they were in conflict with my goals too, but my version no longer would serve Scott's purposes at all, it is much too big and complicated for one thing,

[As of this moment of writing during construction of the Traveller "epsilon" source code release, the Unix "wc()" command claims that Traveller contains 97 source code files, of 33,039 lines of code or 897,299 source code bytes, while this current document in HTML source code form just passed a quarter megabyte in size.]

and by design is never "finished" for another, so any comparison of the two implementations needs to take into account their quite different goals.]

The purposes of the KPD version of the applet Traveller.

I do research programming in computational complexity as a hobby, and the SETSP is the natural choice of the hobbyist programmer. I also needed to learn Java — Sun's platform independent programming language, to have any chance of ever being employed again. Stealing Scott's working code (for which I'd lusted for a couple of years, there were so many things I wanted to change) gave me a chance to start with a functioning framework into which I could introduce new code of the type I understood, while learning more from types new to me as I modified them.

I love to mentor. This code is meant to allow others, just by playing with the applet controls, to gain an intuition and a deeper understanding of how Genetic Algorithms, and this SETSP genetic algorithm in particular, perform both when things are going well, and when problems occur. I wrote this code mostly to teach myself to have that deeper understanding, a gut level understanding of genetic algorithms.

I have no faith in single trick approaches to genetic algorithms. We use a genetic algorithm when we don't understand the problem domain well enough to code an efficient direct solution of the problem, and there is no more reason to suspect that we understand the problem domain well enough to select a single heuristic that will work for all data sets.

I do have "faith" in kitchen sink approaches to genetic algorithms, and want to test that faith by showing that genetic algorithms perform better when a mix of heuristics, metaheuristics, and seeding methods are used simultaneously. Thus there are as many algorithms as I could reasonably steal or create embedded in Traveller, with a control panel to turn them on or off as desired. This kitchen sink approach is not original with me, but goes back to early numerical algorithm research literature I read back in the 1960s, long since lost to me. [Other hobbyists, lusting to see their favorite SETSP heuristic running in Traveller's mix, are invited to enter negotiations to send me source code; don't just send it without asking, my email box is small.]

[I have experience of another kind with genetic algorithms, too, which can stand as an object lesson to other programmers. The genetic algorithm concept and resulting mechanism is so immensely powerful, that adding heuristics which are full of bugs and don't do at all what is expected, still can improve the performance of the mix. The genetic algorithm in nature, after all, runs quite adequately off the input of mutation and blind chance, so handing the computer genetic algorithm mechanism a source of genomes that differ in some new way or according to some new distribution of changes, is equally important with handing it a heuristic that is well designed and lovingly crafted. Thus, the rest of the story is that you cannot trust that your algorithm is working as you planned, just because the genetic mechanism can use its output to solve the given (SETSP or other class of) problems, and that such a seductive "testing technique" proves exactly that your heuristic doesn't break the genome badly enough to make it unusable, and nothing much else.]

I was originally coding this application in MITs StarLogo for Java, but that language ran out of steam for me. I am intentionally creating something very complex, and that language has hard-coded limitations on application complexity that started to warp my coding into an unmaintainable mess. It is great for other purposes, and I still use it, but not for an endlessly growing single application. Needing to get away from StarLogo, and not ready to try to write a C++ GUI with the limited tool libraries at my disposal, I decided to turn to Java with its rich abstract windowing interface class collection, and found Scott's applet waiting to be abused.

The Traveller application on the screen.

Traveller has become visually a plethora of framed windows [some that persist, and some pop-up windows that exist only as long as the corresponding parts of the code are running], into which I divided Traveller's screen interface, as my additions overwhelmed Scott's original one window design. The Traveller application now consists of the following main parts.

Sidebar: Adaptive Permutation.

My three original permutation algorithms share some features. Each selects a count of somethings to permute at random. Next it selects those somethings themselves to permute at random. Then it works its way through all possible permutations of those somethings, computing the fitness of each. Last it returns the genome as modified by the one permutation which gives the genome the superior fitness. Quite often this is the identity permutation, and thus the original genome, if things whose permutation doesn't help genome fitness are selected. This is thus a version of the brute force approach, but restricted to permutation sets small enough that we can afford to wait for it to run to completion.

[This brings up the issue that, ideally, a mixed heuristics genetic algorithm package might work better if various heuristics could be slid in and out of the enabled set as the solution effort worked through various phases, which in turn adds the issue of how such phases should be defined at design time and identified at run time. As folks in the academic community say in research reports when laying groundwork for the next grant application: "the need for more study is indicated."]

Since those original three algorithms, I've added many other algorithms to Traveller that share the concept of trying all possible combinations for some subset of the genome, and all benefit from having that subset be small early in the run and only grow as genome fitness approaches optimal.

[I haven't solved the problem of sliding heuristics into and out of the mix, so I approached the problem from another direction. As of the "delta" release of Traveller, the several algorithms dependent in some sense on a permutation limit are adaptive. That is, they work with small permutation sizes early in the run of a problem, when useful permutations are easily found. When long strings of failures to improve anything with small permutation sizes are experienced, the permutation size is bumped until a global upper limit is eventually reached. This has lots of nice consequences.

The various permutation heuristics communicate through the PermutationController class to share information about how many consecutive unfruitful permutations have occurred, and thus judge when it is time to increase the permutation effort level. It is worth noticing that Mutation Rate and permutation adaptability have a fundamental conflict: if all the permutations are doing is undoing the mischief of mutations, then the mechanism for judging when to raise the permutation effort level is inappropriately satisfied to leave it low. It is best to set Mutation Rate to zero when using permutation heuristics, and the permutation adaptation mechanism, to counter the effects of non-zero mutation rates, will by design set the failure rate at which the permutation effort level is bumped at a low enough level that it is shorter than the rate of introduction of new mutations. This makes permutation effort levels rise faster and earlier than is the case in the absence of mutation, since the alternative was not to have them rise at all.]

Several algorithms that don't really permute anything now piggy-back on the run stage information that adaptive permutation attempts to capture, such as Disordered Slide and Ordered Slide, which use the current adaptive permutation limit merely to decide how many codons to slide together. Since the size of the adaptive permutation limit in some sense contributes to the strength of these algorithms, they too provide feedback of success or failure to help adapt the permutation level.

Sidebar: Preserving Population Diversity.

Population diversity can probaby be defined many ways; number of unique genomes compared as a proportion to population size is a very usual choice. From the point of view of Traveller, which has many mechanisms for combining and manipulating genomes, genomes merely being different isn't sufficient. Traveller is attempting to collect together a set of graph edges into a single genome which make that genome the global optimum solution. Most important to Traveller then, is that at any time a high proportion of all those needed edges from the global optimum solution exist somewhere in the population, and that the missing ones are being created sufficiently often to be available when needed.

Traveller is full of very powerful heuristics, but Traveller's test cases, particularly the nested grid layout, are full of pitfalls, too: local optima that are easily entered and that require many precise simultaneous genome changes to exit. This makes it important not to let the powerful heuristics remove all population diversity and leave Traveller with no tools useful in escaping a local optimum. This is, of course, a balancing act: it would also be nice to see Traveller still able to converge when a global optimum is finally encountered, the tricky part being that while the user can often distinguish local optima from the global optimum or optima, genetic algorithms provide no such capability to Traveller.

Traveller is assisted in avoiding this trap by several features.

Sidebar: Policy in Traveller.

Many times during software development, choices are made about ways to do things that to a casual observer could have been done either way, or in any of a variety of ways. When the programmer feels strongly enough about such a choice to defend it, that choice becomes a policy, and needs documenting. Traveller has many policies, and I have tried to mark the code with comments containing the string "POLICY" where I recognize myself implementing one.

Things I find vastly unsatisfactory about Traveller.

All of these that are under my control, I will fix over time, while my enthusiasm endures. Mostly I lack knowledge and time; the former I will fix, the latter in some sense cures itself, or else you die first.

Bobbles, Blunders, and Miscues

[Or, how those who claim software gets "engineered" would like to deny it really gets built.]

In my first Traveller full-code release "alpha", inver-over was broken, and I didn't even know it. I'd tried to test a polymorphic array to be of the type of one of its content options, and that doesn't work. I was also copying consulted chromosomes, which I only needed to read, in a hot loop, which killed the garbage collector once I got by the first problem. It is fixed now. The more general programming lesson learned is that the messages in exception catches shouldn't be conditionally enabled, they should always be enabled, so that when you write stupid code, you immediately see the complaints shouted in response. The second programming lesson learned is that programmers silly enough to depend on source-code-converter-vendor-supplied garbage collection instead of carefully crafted new() and dispose() calls deserve what happens to them when they fail to pay sufficient attention to garbage collection considerations, which are every bit as tricky to get correct as doing ones own heap maintenance, and a lot harder to isolate when done wrong, because they are implicit rather than explicit in the source code. Sigh.

In my first Traveller full-code release, the routine now called Optimize Nodes Near A Point was severely broken, and I didn't even notice it. I'd committed an "off by one" error in manipulating array indices, and was discarding cities from the genome. If I'd been better at my testing, I would have notice that this routine run by itself crashed Traveller cold, dereferencing null pointers in a few generations. Lesson learned: always test new facilities exhaustively alone, before mixing in other functionality that might hide or compensate for the newly introduced bugs. Sigh.

Does it seem strange to you that Java, which doesn't even support pointers, frequently commits null pointer dereferencing errors? Apparently, though Sun trusted Java enough to write it in Java, they didn't trust pointerless code enough not to give themselves some backdoor way to abuse pointers anyway. This is too bad, and probably makes Java of lower quality than it could have been. I know I'm constantly surprised to be encountering obvious bugs in a compiler this mature. Programming lessons learned: there is no such thing as a mature compiler, and you can definitely trust the build and execution environments to add their flaws to those you create in your code yourself. Sigh.

Probably things work a little better (in the Population class) since I fixed Scott's inputs to his roulette wheel for genomes, which were assigning the widest roulette wheel slots to the least fit genomes. This was compensated for, and his code worked at all, because he was also assigning the full fitnesses, rather than some value modeling the fitness differences, to the roulette wheel slots, making the slots all nearly equally wide anyway, and the overall power of the genetic algorithm paradigm overcame the incorrectly directed bias and incorrectly proportioned biases his roulette wheel was providing. Sigh.

After bragging endlessly about "fixing" Scott's code, naturally I turn out to have just replaced his bad code with my bad code in some instances. Until Traveller release "epsilon", my ever-so-elegant Ordered Crossover variant was carefully copying the crossover codons in the order they had in the recipient genome, rather than the in order they had in the donor genome, as originally intended, rendering the heuristic "interesting", but not particularly "useful". I didn't discover the blunder until I was creating the table in this document to describe the differences between my version of ordered crossover and Scott's version, and had to go back to look at my code to remember how it worked, which turned out to be "incorrectly". First programming lessons learned: "elegent" doesn't replace "correct" as a figure of merit. Second programming lesson learned: do the documentation as you go along: having to explain what you did is a great debugging aid (the "to suddenly find your error, all you really needed to do was describe your code to a potted plant" trick so familiar to long time programmers and the long-suffering patient fellow programmers who get to hear the code described without ever getting to put in a word of advice before the problem is located), and you don't end up with a huge slug of deferred unpleasant work to face all at once. Sigh.

In an earlier Traveller full-source code release, I said about Elastic Net: "It looked much more impressive in his applet than it does in my code, where I notice the fitness of the tour bouncing up and down as the relaxation progresses, but I don't have access to the tuning parameter descriptions in the research paper from which he developed his code, so perhaps I have mine set poorly. Still, though the "solutions" don't look much like solutions for city counts in the hundreds ... ", which was a slander, and for which I apologize. Sun's buggy quicksort demo code, foolishly adopted by me without thorough testing, which I was using to convey Elastic Net's intermediate solution approximations to Traveller as seed genomes, was the cause of problems I incorrectly attributed to Alexander's nice code. I finally ripped out Sun's code completely and wrote my own quicksort from scratch. Alexander's code does a fine job as far up in city counts as I've yet dared to use it. I then correctly concluded: "... (and Alexander says in his code that I'm outside its design capabilities there), the seed genomes captured from the relaxation are an excellent assist to Traveller." Yes, programmers make social blunders as well as, and sometimes combined with, coding blunders. Sigh.

Text files in the Traveller.jar deliverable.

As files, the Traveller code is divided up into top level routines, routines down Scott's package path, and routines down my package path. Logically, it is further subdivided (by Scott, with me imitating him) into genetic, tools, ui (user interface), and (my addition) structures, where I stuck quicksort and the Sortable interface so that structures implementing Sortable could rest beside them. Besides my code and Scott's code, also incorporated from original sources, all at least somewhat modified by me, are Sean Luke's port of the Mersenne Twister to Java, Alexander Budnik's Elastic Net code, the nice little MultiLineLabel class from the VoroGlide distribution (attributed there to Christian Icking, Rolf Klein, Peter Köllner, and Lihong Ma), and (already included in Traveller's sourc code, and compiled, and linked in Traveller's build kit, though not yet implemented into Traveller or used there) a big chunk of the Qhull distribution which will become my Delaunay Triangulation seeder someday after Herculean redesign effort and rewrites still to be done (it is a long integer location coordinates algorithm, I need a double precision float algorithm, for starters, and my triangulation will need many more structures, annotations, and markup points than Qhull's makes available). Published algorithms not available as code are credited where the authors are known. I have lost track of the origin of the Fortran 66 permutation generator code I copied from the Net and ported, but it works well and fast, however mysteriously; thanks to the original author, wherever you may be.

Besides code, the Traveller.jar file includes documentation files, build tool scripts, and license documents.

Here is just a comment about each file, usually brief, to help you find stuff. As in Star Wars, if you really want to understand Traveller, Use the Source, Luke!

Coding conventions, a rant.

The contributions made by KPD to Traveller do not follow the Sun coding conventions as found at http://java.sun.com/docs/codeconv/ . More than that, when I maintain other people's code that uses them, I rip them out. This is not out of perversity, or of ignorance of those conventions. I read them and rejected them, for good and sufficient reasons. They constitute premature standardization on an inferior 1972-era poorly considered style of coding chosen for C. They do not have the quality, for example, of my own intuitive, unformalized coding conventions, developed over 41 years. Those Sun conventions seem designed by minds too warped by existing C usage to take a fresh look at what works as opposed to what is common practice. They also ignore realities of cheaper disk storage, better, multi-windowing text editors, and better understanding of human interface issues (like what makes code readable) that have arisen since the C coding conventions were developed in 1972. I'm wasting some time and space here to justify myself before the swat teams arrive.

Explicitly: