This course is about programming and artificial intelligence. Depending on what school you're at, that could mean robots, neural networks, chess playing, etc.
This course is about
- designing and implementing intelligent components using symbolic knowledge representation
- 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
- XML and HTML based methods for knowledge interchange
- software engineering
Symbolic Knowledge Representations
This includes
- deductive logic to implement symbolic inference and problem solving
- frames to represent real world concepts
- Semantic Web knowledge exchange technologies such as OWL
Software Development
This is also a course on software development. This is not a course for writing throw-away code. Your coding 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?
Most students think this is the order of importance, but in fact clarity is more important than correctness or efficiency:
- If code is clear but buggy, it can be corrected.
- If code is clear but slow, it can be optimized.
Every company is burdened with legacy software that is so unmaintainable it can't be fixed or improved, only replaced.
This is why the Automated Lisp Critic and the online critiquing process are central to this course. They are all about learning to write clear code, in any language.
Correctness
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 turns 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.
This is why I developed the easy-to-use lisp-unit package and why all the core exercises have tests your code must pass before being submitted.
Efficiency
There are two key rules for optimizing code often overlooked by beginners:
- Don't optimize until you need to.
- Profile first.
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 two general techniques that can be used to speed up rules and patterns dramatically, without increasing code complexity.
- discrimination trees
- pattern and rule compilers