home *** CD-ROM | disk | FTP | other *** search
- Chapter 5 A Little Math
-
-
-
-
- Besides dealing with symbolic facts, CLIPS can also perform calculations.
- Although CLIPS was not designed for efficiency in number crunching,
- it can do a wide variety of math operations. You'll find the computational
- capability of CLIPS useful in many applications.
-
-
- Two Packages
-
-
- CLIPS is available in different packages so that you can customize it to fit
- your needs. The standard CLIPS kernal provides only the basic arithmetic
- operations such as addition, subtraction, multiplication and division.
- The CLIPS source disk has both the kernal as well as a math library of C
- routines. You can link and compile this library with the kernal
- to produce an enhanced CLIPS with a very powerful library of math functions.
- The math library is included as an example of how users can enhance
- CLIPS to suit their needs. The disadvantage of the math library version of
- CLIPS is that it adds to the size of CLIPS. The amount of extra
- memory required will depend on your compiler.
- An expert system language like CLIPS is not designed to produce application
- programs that do a lot of calculations. Although the math functions
- of CLIPS are very powerful, they are primarily meant for modification of
- numbers that are being reasoned about by the application program.
- Other languages such as FORTRAN are better for number crunching in which
- little or no reasoning about the numbers is done.
-
-
- Let's Be Precise
-
-
- Since CLIPS is designed for portability, it can be put on many different models
- of computers. However, different models usually treat numbers
- in different forms. You should work through the examples in this chapter
- carefully on your computer and note any differences.
- In particular, any rules which depend on a numeric value in a conditional
- element may lead to problems in portability of CLIPS code from one
- model of computer to another. All of the examples in this book were done on
- an IBM PC XT and should be fairly close to what you'll see on other
- computers using single-precision, floating point arithmetic.
- As an example of the way CLIPS displays numbers, enter the following
- (deffacts) or just (assert) the numbers.
-
- (deffacts math
- (0)
- (1)
- (-5)
- (1.5)
- (-.000123456)
- (123456)
- (1.33e7)
- (2.5e+4)
- (-6.924e-10)
- (1e50)
- (1e-50))
-
- After you do a (reset), check (facts) and you'll see facts like the
- following. Brief comments have been inserted to explain the facts while
- a more detailed discussion follows.
-
- f-1 (0)
- f-2 (1) ;really floating point, just appearance of integer
- f-3 (-5) ;see note for f-2
- f-4 (1.5) ;unchanged appearance from asserted fact
- f-5 (-0.00012346) ;note round-off to five significant digits
- f-6 (1.2346E+05) ;see note for f-5,also exponential notation
- f-7 (1.3300E+07) ;false precision displayed
- f-8 (25000) ;see note for f-2,also now fixed notation
- f-9 (-6.9240E-10) ;see note for f-7
- f-10 (3.4028E+38) ;this fact and
- f-11 (0) ;this one are not correct because they exceed the numeric
- limits of the compiler used for CLIPS. Different compilers will
- have different limits.
-
- Even the appearance of facts can be deceptive if the numbers
- exceed the range allowed by the compiler you used for CLIPS. For example, on
- some compilers, the asserted fact (1e-50) might be really stored
- as 0 if it's smaller than the smallest number allowed by the compiler. On
- other compilers, it might really be stored as 1e-50.
- Numbers whose absolute magnitude are smaller than 0.0001 or greater than or
- equal to 100000 will be expressed in exponential notation. Numbers
- with absolute magnitude from 0.0001 to less than 100000 will be expressed in
- fixed form, even if entered in exponential notation.
- The precision of a number refers to how many significant digits it has. For
- example, the numbers 1.23e-3 and 0.000123 both have three significant
- digits. Leading zeroes do not count in determining the number of significant
- digits.
- The accuracy of a number refers to the truth of the number. For example,
- suppose the height of a chair is measured with a ruler which has
- divisions to a millimeter as 0.712 meters. Then suppose the same chair is
- measured with another ruler which has rulings of only tenths of a
- meter as 0.4 meters. Notice that the measurements are quite different. Which
- is correct? At first you might say that the 0.712 reading is
- correct since it has more significant digits. But that is not necessarily so.
- It could be that the first ruler was incorrectly calibrated.
- While 0.712 is certainly more precise it may not be more accurate.
- The precision and range of numbers in CLIPS will depend on the compiler that
- you use to compile it. CLIPS will normally show five significant
- digits and this should be the same in all implementations. However, the
- internal precision in which numbers are represented may vary from one
- compiler to another and this can affect the triggering of rules.
- Sometimes a false precision can be shown, as in the case of f-7. Note that
- the asserted fact (1.33e7) has only three significant digits and
- yet CLIPS shows five significant digits. Although leading zeroes are not
- significant, trailing zeroes are significant. So 1.3300E+07 is shown
- as if it was known more precisely. All we really know is that the original
- asserted fact of 1.33e7 was within the range 1.334e7 to 1.330e7.
- A number greater than 1.334e7 would have been expressed as 1.35e7 while a
- number smaller than 1.330e7 would have been written as 1.29e7.
- The appearance of false precision arises because CLIPS is designed to always
- show five significant digits. However, the false precision will
- not hurt your calculations since it is just the displayed appearance. It's
- only important that when you interpret the final results that you
- realize they cannot be more precise than the most imprecise number.
- As an example of how the precision of numbers affects rule firing, enter the
- following.
-
- (defrule num-check
- (1.5)
- =>
- (printout "valid number" crlf))
-
- When you (assert (1.5)) the rule will fire. Now retract the fact and assert
- 1.5000001. On an IBM PC where CLIPS was compiled with the Lattice
- C Compiler, the fact was stored as (1.50000012) as shown by a (facts). In
- this case the rule would not fire. However, if the fact 1.50000001
- was asserted, the fact was stored as 1.5 and so the rule did fire.
- Depending on your implementation of CLIPS, you may need more zeroes to make
- the rule fire. But eventually, the number that you assert will
- be less than the precision of CLIPS and the rule will fire. So if you design
- a program with conditional elements which include numbers, you
- should consider the precision and range of numbers that will cause erroneous
- rule firings. Conditional elements which depend on numbers should
- be examined very carefully, especially if you plan to run the program on a
- different model of computer later.
- If you need a lot of precision with decimal numbers, be careful since most
- compilers produce code using binary number representation. This
- can lead to inaccurracy and imprecision. For more details on binary numbers
- and imprecision, see BASIC: Advanced Concepts by J. Giarratano,
- published by Howard W. Sams, Inc.
-
-
- It's Elementary
-
-
- CLIPS provides the elementary arithmetic operators as shown in the following
- table.
-
- CLIPS Operators
- + addition
- - subtraction
- * multiplication
- / division
- ** exponentiation
-
- All arithmetic and numbers are in floating point.
- Numeric expressions are represented in CLIPS according to the style of LISP.
- In LISP and CLIPS, a numeric expression that you would customarily
- write as 2 + 3 must be written in the LISP and CLIPS prefix form, (+ 2 3).
- The customary way of writing numeric expressions is called infix
- form because the math operators are in between the operands or arguments. In
- the prefix form of CLIPS, the operator must go before the operands
- and parentheses must surround the numeric expression.
- One way of evaluating a numeric expression in CLIPS is using the =
- comparison function in an (assert) action. The general form of an arithmetic
- calculation in CLIPS with two arguments is
-
- (operator arg arg)
-
- where "operator" can be any of the arithmetic operators and "arg" stands for
- the argument used by the operator.
- To see how these arithmetic operations perform on your computer, enter the
- following rules, then assert (numbers 2 3) and run. Also shown
- by each rule is a comment describing what each rule does. Note that the
- comment is in infix notation for your information only. Infix cannot
- be used in a rule.
-
- (defrule addition
- (numbers ?x ?y)
- =>
- (assert (=(+ ?x ?y)))) ; ?x + ?y
-
- (defrule subtraction
- (numbers ?x ?y)
- =>
- (assert (=(- ?x ?y)))) ; ?x - ?y
-
- (defrule multiplication
- (numbers ?x ?y)
- =>
- (assert (=(* ?x ?y)))) ; ?x * ?y
-
- (defrule division
- (numbers ?x ?y)
- =>
- (assert (=(/ ?x ?y)))) ; ?x / ?y
-
- (defrule exponentiation
- (numbers ?x ?y)
- =>
- (assert (=(** ?x ?y)))) ; ?x ** ?y
-
- After you run, check the facts. The answer for division will probably show a
- round-off error in the last digit.
- At the present time, CLIPS is not designed to evaluate numeric expressions
- at the top-level. So you cannot assert a top-level command like
- (assert (=(+ 2 3))). Numeric evaluation must be done within a rule.
- In a rule, you can assert other atoms along with a numeric expression. For
- example, the addition rule could be
-
- (defrule addition
- (numbers ?x ?y)
- =>
- (assert (sum =(+ ?x ?y))))
-
- Be sure to put a space between the atom "sum" and the following "=". Remember
- that a space must separate atoms in a fact. The "=" tells CLIPS
- to evaluate the following fact before asserting it. So "=(+ ?x ?y)" is
- evaluated as 2 + 3 = 5 and the resulting atom of 5 is used for the assertion
- (sum 5). Run this version of the rule and you'll see the fact (sum 5).
-
-
- Extensive Arguments
-
-
- The arguments in a numeric expression can be extended beyond two for all
- operators except exponentiation. The same sequence of arithmetic calculations
- is performed for more than two arguments. The following example shows how
- three arguments are used. Evaluation proceeds from left to right.
-
- (defrule addition
- (numbers ?x ?y ?z)
- =>
- (assert (=(+ ?x ?y ?z)))) ; ?x + ?y + ?z
-
- (defrule subtraction
- (numbers ?x ?y ?z)
- =>
- (assert (=(- ?x ?y ?z)))) ; ?x - ?y - ?z
-
- (defrule multiplication
- (numbers ?x ?y ?z)
- =>
- (assert (=(* ?x ?y ?z)))) ; ?x * ?y * ?z
-
- (defrule division
- (numbers ?x ?y ?z)
- =>
- (assert (=(/ ?x ?y ?z)))) ; ?x / ?y / ?z
-
- Enter the above program and assert (numbers 2 3 4). After you run the
- program, you'll see the following facts. Note that the division fact,
- f-5, may be different on your computer because of the compiler you used for
- CLIPS.
-
- f-2 (9)
- f-3 (-5)
- f-4 (24)
- f-5 (0.16666667)
-
- The infix equivalent of a multiple argument CLIPS expression can be
- expressed in the following general way.
-
- arg operator arg operator arg operator arg ...
-
- where the dots, "...", symbolize the pattern repeated. Another way of
- symbolizing this is
-
- arg [operator arg]
-
- where the square brackets mean that there can be multiple terms. Note that you
- cannot write a CLIPS expression with dots or square brackets.
- The dots and brackets are just a shorthand notation.
-
- Mixed Results
-
-
- Mixed calculations can also be done in the prefix notation. For example,
- suppose you want to evaluate the infix expression
-
- ?x + ?y * ?z
-
- One important fact about CLIPS and LISP calculations is that there is no
- built-in precedence of arithmetic operations. That is, in other computer
- languages, multiplication and division rank higher than addition and
- subtraction and the computer does the higher ranked operations first.
- However, in LISP and CLIPS, there is no built-in precedence. Everything is
- simply evaluated from left to right with parentheses determining
- precedence.
- In the example of ?x + ?y * ?z, the customary way to evaluate it is to
- multiply ?y by ?z and then add the result to ?x. However, in CLIPS,
- you must explicitly write the precedence. The example would be written in the
- following rule.
-
- (defrule mixed-calc1
- (numbers ?x ?y ?z)
- =>
- (assert (result =(+ ?x (* ?y ?z))))) ; ?x * ?y + ?z
-
- In this rule, the innermost parentheses is evaluated first and so ?y is
- multiplied by ?z. The result is then added to ?x. Also, note that you
- don't need an "=" function until the final atom is to be asserted. That is,
- you don't need to put an "=" in front of every operation in parentheses.
- If you wanted ?x + ?y * ?z, where again multiplication is done first, the
- rule would be
-
- (defrule mixed-calc2
- (numbers ?x ?y ?z)
- =>
- (assert (result =(+ (* ?x ?y) ?z)))) ; ?x * ?y + ?z
-
- Enter and run these rules for the (numbers 2 3 4) and see if the results are as
- expected.
-
-
- Binding Things Up
-
-
- In order to print out the value of a math calculation, the result must first be
- bound to a variable using the bind function. The bound variable
- can then be printed out. For example,
-
- (defrule addition
- (numbers ?x ?y)
- =>
- (assert (answer (=(+ ?x ?y))))
- (bind ?answer (+ ?x ?y))
- (printout "answer is " ?answer crlf))
-
- Enter and run this and you'll see that the answer is printed out as well as
- asserted.
- Notice the difference in syntax between the (assert) with its "=" function
- and the bind which does not use the "=". The bind function does
- not use the "=" because CLIPS assumes that whatever follows the variable
- argument in a bind should be evaluated. In contrast, when CLIPS encounters
- an (assert), it does not know at first if an argument is to be evaluated. So
- an "=" is necessary to tell CLIPS that the argument in the (assert)
- should be evaluated.
-
-
- What's At The Root
-
-
- The math functions can return a value if they are bound to a variable using the
- bind function. The following example shows how the square root
- function is first bound and then printed out.
-
- (defrule square-root
- (number ?value)
- =>
- (bind ?answer (sqrt ?value))
- (printout "square root of " ?value " is " ?answer crlf))
-
- To run, first assert a fact such as (number 4).
- The bind function can be used to bind any atom to a variable. For example,
-
- (defrule bind-test
- (number ?value)
- =>
- (bind ?answer ?value)
- (printout "answer is " ?answer crlf))
-
- will bind ?answer to ?value. Try running this after asserting (number 4) and
- you'll see the answer of 4.
- Math functions can be included in arithmetic expressions using prefix
- notation as shown following.
-
- (defrule square-root
- (number ?value)
- =>
- (bind ?answer (+ 4 (sqrt ?value)))
- (printout "square root of " ?value " is " ?answer crlf))
-
- If you assert (number 4) and run, you'll see the answer of 6 printed out from
- ?answer. Math functions are treated just like any other argument
- in a numeric expression, except that they require parentheses around them.
-
-
- Math Functions
-
-
- Following is a list of the math functions in the math library. To access these
- functions, you must first link the library to the CLIPS kernal
- and compile it to produce the math version of CLIPS. The math version will
- execute just like CLIPS with the added enhancement that you can
- access all of the following math functions.
-
- Note: all trig functions are expressed in radians.
- <fun> stands for a function.
- <arg> stands for the one argument of the function.
-
-
- Trig And Hyperbolic Functions
-
- Format : (<fun> <arg>)
-
- Example: (defrule trigtest
- (number ?value)
- =>
- (bind ?z (sin ?value)))
-
- (assert (number 1))
-
- In the above example, ?z will be bound to the sine of 1.
-
-
- Standard Trigonometric Functions
-
- sin
- cos
- tan
- sec
- csc
- cot
-
-
- Inverse Trigonometric Functions
-
- acos
- asin
- atan
- asec
- acsc
- acot
-
-
- Hyperbolic Functions
-
- cosh
- sinh
- tanh
- sech
- csch
- coth
-
-
- Inverse Hyperbolic Functions
-
- acosh
- asinh
- atanh
- asech
- acsch
- acoth
-
-
- Maximum And Minimum Functions
-
- The following functions return the minimum and maximum of a set of numbers.
- The double angles, "<<" and ">>", around the arguments indicate
- one or more arguments are allowed.
-
- Format : (<fun> <<arg>>)
-
- min : returns the minimum argument
-
- max : returns the maximum argument
-
- Example: (defrule test
- (numbers ?x ?y)
- =>
- (bind ?z (min ?x ?y)
- (bind ?w (max ?x ?y)))
-
- (assert (numbers 2 3))
-
- In the above example, ?z will be bound to 2.
- ?w will be bound to 3.
-
-
- Modulus Function
-
- The modulus function returns the modulus of the first argument by the second
- argument. The modulus is defined as the integer result of division
- of the first argument by the second. Since CLIPS deals only with floating
- point numbers, the modulus is returned as a floating point number
- instead of the standard integer.
-
- Format : (mod <arg> <arg>)
-
- Example: (defrule modtest
- (numbers ?x ?y)
- =>
- (bind ?z (mod ?x ?y))
-
- (assert (numbers 3 2))
-
- In the above example, ?z is bound to 1.
-
-
- Log Functions
-
- log : returns the log to base e
-
- log10 : returns the log to base 10
-
- Format : (<fun> <arg>)
-
- Example: (defrule logtest
- (number ?value)
- =>
- (bind ?z (log ?value))
- (bind ?w (log10 ?value)))
-
- (assert (number 5))
-
- In the above example, ?z will be bound to the log of 5 while ?w
- will be bound to the log to base 10 of 5.
-
-
- Exponential Function
-
- exp : returns e raised to the power of the argument,
- that is, e**arg
-
- Format : (exp <arg>)
-
- Example: (defrule exptest
- (number ?value)
- =>
- (bind ?z (exp ?value)))
-
- (assert (number 1))
-
- In the above rule, ?z is bound to exp of 1.
-
-
- Square Root
-
- sqrt : returns the square root of the argument
-
- Format : (sqrt <arg>)
-
- Example: (defrule sqrtest
- (number ?value)
- =>
- (bind ?z (sqr ?value)))
-
- (assert (number 4))
-
- In the above example, ?z is bound to the square root of 4.
- Problems
-
-
- 1. Check the limits of accuracy on your computer. Assert
- (number 1e-38)
- (number 1e-50)
- (number 1e-70)
-
- and see how often the rule
-
- (defrule test-limit
- (number 0)
- =>
- (printout "Rule fires" crlf))
-
- fires. Use (watch rules) and (watch facts) commands to see which facts are
- triggering the rules. Assert other numbers to narrow down the limit
- of the largest number that will be interpreted as 0.
-
-
- 2. Write a program to calculate the area of various geometric shapes. If the
- user asserts one of the following facts, the program will calculate
- and print out the area. If something is asserted that is not one of the
- shapes shown, the program should print out an error message. Run for
- the examples shown. For Pi, assert (Pi 3.14159).
-
- Examples Meaning Area
- (square 10) (square side) S * S
- (triangle 6 20) (triangle base height) 1 / 2 * B * H
- (rectangle 5 3) (rectangle length width) L * W
- (circle 3) (circle radius) Pi * R * R
-
-
-