This course is about programming and artificial intelligence. Depending on what school you're at, AI could mean robots, neural networks, chess playing, etc.
This course is about these aspects of AI, from a programmer's perspective:
- designing and implementing intelligent components using symbolic knowledge representation
- using and sharing semantic knowledge over the web
- developing tools for authoring the knowledge needed by such systems
- doing it all with maintainable code
In particular, the main topic areas of this course are
- symbolic knowledge representation techniques using Common Lisp
- JSON and HTML based methods for knowledge interchange
- software engineering
Symbolic Knowledge Representations
This is also a course on software development. The course is made up many exercises and challenges. Your solutions will be evaluated on three classic criteria:
- correctness-- does the code do what it's supposed to?
- efficiency -- does the code run fast enough?
- clarity -- is the code easy to understand?
Of these, clarity is more important than correctness or efficiency:
- Clear code can be corrected.
- Clear code can be optimized.
- Unclear code is hard to impossible to correct or optimize.
Critical to correct code is testing -- lots of it. This has been known since programming began. Unfortunately the traditional development process was to get the requirements, design a solution, implement, and test. This meant that testing always occurred at the end, when the project was late, time was short, pressure was high to deliver, etc. As a result, most code has been delivered with little or no testing.
In a brilliant move, modern agile development turned this process on its head: tests are written -- and run! -- as part of the requirements development process. Test-driven development is a simple idea with major impact. It takes a while to get used to it but once you do, you'll never feel secure about writing code with no tests.
For this course, we use the lisp-unit package. Virtually all the book and AI exercises have tests your code must pass before being submitted.
There are several key rules for optimizing code often overlooked by beginners:
- Don't optimize until you have a bottleneck.
- Profile the code to locate the bottleneck.
- Remove bottlenecks with easy-to-apply well-understood techniques.
Violating the first rule is called premature optimization. Programmers trying to write clever fast code end up wasting precious development time, produce fragile unreadable code, and usually have for no measurable gain in speed.
Violating the second rule occurs because programmers' intuitions about what part of a code is the bottleneck are almost always wrong. We focus on the complicated parts but the real culprit is almost always some very frequently called routine that is too simple and basic to even catch our eye. Commercial Lisps come with very slick tools to measure time spent in a program but even crude hand-written calls to measure time are usually sufficient to identify the major bottlenecks.
In symbolic AI programs, the very source of power in AI programs, namely rules and patterns, can be a source of inefficiency. Fortunately, there are a few general techniques that can be used to speed up rules and patterns dramatically. While the libraries that implement these techniques may be complex, the changes to your own code to use them are not.
- caching, using hashtables.
- discrimination trees
- pattern and rule compilers