Functions can operate on sheets in two ways. They can request data from scheme, item by item. This is useful for inspection and debugging (e.g. examining values in one local neighborhood). However, it is extremely inefficient if you plan to access a large number of elements. Large jobs should be performed by defining a function that will be downloaded to the coprocessor.

A typical computer vision operation might consist of a scheme function which calls one or more coprocessor functions. The scheme function does any high-level work (user interface, graphics, analysis of input parameters) and allocates storage (sheets). The coprocessor functions scan or trace through sections of the data sheets, applying code at each location.

The compiler for coprocessor functions supports only a limited subset of Scheme and Envision operations. The restrictions on the user-level language are documented below. They are imposed to ensure clean style and efficiency of compiled code.

Coprocessor functions are defined as follows

(bulk-define name input-types output-types lambda-expression) e.g. (bulk-define test (integer integer) (real) (lambda (x y) (sqrt (+ x y))))

This mimics the standard mathematical convention for defining a function "let f be a function from ZxZ to R, such that f(x,y) = sqrt(x+y)".

The input types must be specified because the compiler must be able to infer all types. (In particular, it must be able to distinguish integers from reals.) If functions were compiled in the right order, we could (in principle) infer output types. We require them to be specified

- so that functions can be compiled out of order,
- to assist in error checking, and
- for consistency with mathematics.

The input and/or output typelist can be declared as the null list (), or equivalently using the type name unspecified.

An unspecified declaration for the output is appropriate if the lambda form does not return an output value, e.g. it ends with (values) or (set! a 3). It is also appropriate if the lambda form returns a value of varying type, e.g. (if test 3 4.0). The coprocessor allows such forms but, because it must resolve types at compile type, requires that their value never be used. Finally, the output type can be declared as unspecified when the lambda form returns a value but the user intends to ignore it, likely to be common when the top-level form is scan.

If the output is specified as a real point (of any dimension) and the compiler discovers that the function actually produces an integer point (of the same dimension), an exact->inexact coercion is added automatically during compilation.

When the input or output is a single number, it can be specified as a bare item or as a list with one element. The two are equivalent. This follows the standard convention for defining functions between topological spaces in pure mathematics.

For curiosity, debugging, and error reports, the compiler can report intermediate stages of its work. Use the command

- (adjust-compiler-chatter k)

k should be an integer between -1 and 5. The default is 0: it echos the type of the newly created function. Higher values cause more detail to be reported. A value of -1 causes it to become entirely silent.

The function calling mechanism also times calls to coprocessor functions. To have this information printed (or not printed) for your inspection, use the following functions:

- (c-timer-on)
- (c-timer-off)

This works well in combination with the scheme48 ,time command. Notice that the scheme48 command reports only that part of the CPU time consumed by Scheme48, not the time consumed the coprocessor.

The following types are allowed in user-defined coprocessor functions, and as inputs and outputs of such functions.

- integer (always exact)
- real (always inexact)
- booleans
- unspecified (e.g. as the output type if the function returns no value)
- (real-point n)
- (integer-point n)
- (manifold n m)
- (real-grid n m)
- (integer-grid n m)
- (manifold-sample n m)
- (real-grid-sample n m)
- (integer-grid-sample n m)

Coprocessor functions do not support complex numbers or exact non-integers (fractions). If exact non-integer real numbers are passed as arguments to coprocessor functions, the interface will convert them to inexact reals. Inside coprocessor functions, operations which might be expected to produce an exact non-integer real (e.g. dividing one integer by another) produce an inexact real.

The coprocessor also does not distinguish inexact integers from other inexact reals. This should not affect the behavior of a legal scheme form. However, the function inexact->exact will not generate an error if applied to non-integer values. The output will be the nearest integer, but the user should not depend on which definition of "nearest" is applied.

The parameters n and m describe the dimensionality of the object. For example, a (manifold 2 3) is a manifold with a 2D domain and a 3D codomain. A (scanner 2) is a scanner for a sheet with a 2D domain. A (real-point 2) is a point in 2D with real coordinates.

Dimensionality of sheets and associated objects (e.g. sample) must be determined at compile-time because it has a massive effect on the design of algorithms (from the user's point of view) and on the low-level code inside the compiler (from that of the implementer). For similar reasons, the distinction between reals and integers must be determined at compile-time. Other distinctions between different types of objects are handled at run-time, either it can be done without loss of efficiency (e.g. the distinction need never be made inside a fast inner loop) or because a compile-time distinction would result in excessive amounts of duplicative code.

Notice that (real-point 1) is synonymous with real, and similarly for integer points. Again, this follows the conventions of pure mathematics.

The sublanguage is largely defined by forbidding use of certain functions. The supported functions and special forms are listed below. In a few cases, however, there are restrictions on the usage of supported forms.

- Functions expecting a boolean input must be given a boolean. Numbers, sheets, and other random sorts of objects are not acceptable alternatives to #t.
- The function = can only be applied to exact inputs.
- The functions quotient, remainder, and modulo can only be applied to exact inputs.

A form headed by if can be used as input to another form only when its output type is well-defined (not unspecified). This means that it must be a binary if. The type of both branches must agree, or it must be possible to make them agree by running one through exact->inexact, or one branch must generate an error. These restrictions do not apply if the output of the if form is not used.

Control structure: if, set!, cond, let, let*, begin, do, values, receive

Type coercion: inexact->exact, exact->inexact

Boolean operations: and, or, not

Numerical tests: =, <=, <, >, >=, odd?, even?, zero?, positive?, negative?

Numerical functions: +, -, *, /, max, min, remainder, quotient, modulo, abs, floor, ceiling, round, truncate, log, exp, expt, sqrt, sin, cos, tan, asin, acos, atan, bitwise-not, bitwise-and, bitwise-ior, bitwise-xor, arithmetic-shift

pi

Handling missing values: missing?, make-missing

Arithmetic functions: random-real, dot-product, cross-product, vector-magnitude

Control structure: multiple-set!, expect, scan

Numbers and points: make-point, point-coordinate

Sheets: sheet-ref, sheet-min-sample, sheet-max-sample, focus-min-sample, focus-max-sample

Samples: nearest-sample, sample-ref, sample-set!, sample-erase! sample->point, shift-sample, sample-=, sample-<, sample->, sample-<=, sample->=, sample->sheet, sample-offset

Ownership, Maintenance and Disclaimers

Last modified