Getting Started


This page will help you get started using Envision.


To start using Envision, first set up your init files. Then restart (or restart) emacs. The command M-x run-scheme inside emacs should then start envision.

When Envision starts, it will print something like:

   Welcome to Scheme 48 0.46 ENVISION (14 April 97).
   Copyright (c) 1993, 1994 by Richard Kelsey and Jonathan Rees.
   Copyright (c) 1996 by NEC Research Institute, Inc.
   Please report bugs to scheme-48-bugs@martigny.ai.mit.edu.
   Type ,? (comma question-mark) for help.

Before you can do anything interesting inside Envision, you must start the coprocessor, using the command:


If you get an error claiming lack of memory (or the like), that's probably what your problem is. On certain versions of Unix (e.g. AIX and Solaris), there is a per-user limit on the amount of memory a process can consume: use the shell command limit to see your limits and reset them. On linux boxes with limited RAM, make sure you have enough swap space and that swapping is working correctly.

If you get an error reporting that it cannot start the socket, reset scheme48 (e.g. type ctrl-d to get a prompt and then ,reset) and then retry the command. On some machines, you can reduce the chance of such an error by waiting a moment or two between getting the scheme48 prompt and issuing the (start-coprocessor) command.

When the coprocessor starts, it will print something like:

   Welcome to ENVISION!

   Daniel E. Stevenson and Margaret M. Fleck
   Version 0.21

   Please send all bug reports to envision-bugs@cs.uiowa.edu

   Starting the coprocessor binary at: /group/scheme/envision/bin/hp/icp

   Connect to coprocessor (y/n)? 

Answer both of its questions with y, followed by a carriage return. If you get an error such as the following, right after answering the first question, restart scheme and re-try the process but answer the questions more slowly. Count to two or something before answering the first question. (No, you really don't want to know why.)

   Error: exception
          (vm-extension 23 '(3 "localhost" . 5000))

When you have answered both questions, the coprocessor should report how many user-defined functions it has loaded (probably zero at this stage) and you should get a Scheme48 prompt (>). You are now ready to start using the system!

Some new data types

Envision includes a new data structure called a "sheet." Sheets are used to represent large blocks of data, such as an image plane or a 1D list of coordinates for a region boundary.

Envision includes basic data types for 2D and 3D points. Numbers are regarded as equivalent to 1D points. 2D and 3D points are created using the function make-point. A number of basic arithmetic operations, such as +, are are defined on higher-dimensional points ( details).

  (define xx (make-point 2 3))
  (define yy (make-point 1 4))
  (point? xx)
  (point? 3.0)
  (+ xx yy)

The class of points also includes a new value "missing." This value is returned when a numerical value is not available. For example, (atan 0 0) returns a missing value. (Currently works only inside coprocessor functions: a bug.) References outside the explicitly stored values in a sheet return a missing value. Missing values can be created using the function make-missing.


Defining a coprocessor function

Functions that will run on the coprocessor are defined using bulk-define. Most coprocessor functions manipulate sheets, otherwise they might as well run in the main scheme interpreter. However, it may help you to first experiment with simple numerical functions. For example, here is the Envision version of the factorial function.

  (bulk-define fact integer integer
     (lambda (x) 
       (expect (>= x 0))
       (cond ((<= x 1) 1)
             (#t (* x (fact (- x 1)))))))

When you evaluate this form, Envision should print a message announcing that it is adding the function fact. You can then run fact as if it were a normal scheme function, e.g.

   (fact 3)

The inputs to bulk-define are, in order: the function name, the input type(s), the output type(s), and a lambda expression. Input and output types must be declared, because they cannot be inferred (in general) from the lambda expression and efficiency demands that types of variables within the new function be determined at compile time.

The new procedure expect provides a limited ability to generate error breaks from within coprocessor functions. (expect bool) returns an unspecified value if bool is true, and generates an error break if bool is false. Notice that non-integer inputs to fact will be caught by type checking at the interface between scheme and the coprocessor.

In general, a coprocessor function can take any number of inputs and/or return any number of outputs. For example, the function vect-combine accepts multiple input values and the function split returns multiple values.

  (bulk-define vect-combine ((integer-point 2) (integer-point 2))  
                            (integer-point 2)
    (lambda (x y) (* 2 (+ x y))))

  (bulk-define split integer (integer integer)
    (lambda (x) (values x (* 2 x))))

Notice the format for the type declarations. The type names integer and (integer-point 1) are equivalent. Other handy type name are real, boolean, and (real-point k) where k is an integer. Multiple values are indicated by giving a list of types in place of a single type. The empty list () or (equivalently) the type name unspecified can be used indicate that the function expects no inputs and/or returns no outputs.

For example, the function random-output takes no inputs and returns a random value between 0 and 10.

   (bulk-define random-output () real
        (lambda () (random-real 0.0 10.0)))

Before proceeding to functions handling sheets, you may wish to examine more simple examples and perhaps skim the manual pages on user-defined coprocessor functions.

Functions for handling sheets

Examples of sheet-manipulating functions. Manifolds.

Note: use small example images!

Files and windows

Geometrical data types: line-segment, polygon, ellipse (circle)

Opening/closing windows, files. Reading objects from file, displaying to window. Including integer-grids.

Compiling Functions into C

Coprocessor functions created using bulk-define run interpreted, on the coprocessor's stack machine. This is handy for learning and debugging, but the interpreter runs rather slowly. Eventually, you will want to generate C code for your functions and link them directly into the coprocessor binary. This will make them run much faster: our preliminary experiments suggest that the difference is more than an order of magnitude.

First, if you have not already done so, set up your private coprocessor directory and re-compiled the basic coprocessor binary in this private directory. The following directions assume that your private directory is named envision-private/coprocessor-code and that you are compiling for only one architecture. See the user manual for additional details and options.

The function that is used to compile code into C is dump-c-functions. It takes one input, a list of function names. For example:

  (dump-c-functions '(fact split))

The functions in your list must all have been defined with bulk-define (in the current Scheme session) and compiled successfully (so they run in interpreted mode). The functions in the list must not call any user-defined functions not in the list. This is because a C function linked directly into the coprocessor can only call other directly-linked C functions, not interpreted coprocessor functions.

The dump command will create two new files in your private coprocessor directory: "user-functions.h" and "user-functions.c" These files contain all new new C code for the functions you dumped. Once you have created these new files, you must make a new binary of the coprocessor with the new code included.

  cd ~/envision-private/coprocessor-code

If mysterious problems happen during compilation, try issuing the following commands prior to the make command.

  make distclean
  make clean

This will create a new binary coprocessor file in this directory called "icp". Move it to your binary directory, perhaps renaming it, and update your coprocessor init file (.envision-init) to contain its pathname. Quit Scheme, and then restart Scheme and the coprocessor. Start-coprocessor should report that it has started your new binary.

Your dumped C functions are automatically loaded into the new binary. However, they appear to live in their own package. The special-form bulk-import is used import their names into your local package.

  (bulk-import fact)
  (bulk-import split)

Notice that the names are not quoted. When the names have been imported, you can call the new functions.

Normally, your code package will contain both coprocessor functions and functions running in Scheme. Separate these into different source files, and include the bulk-import forms in the same files as the Scheme functions. After you start Envision with the new coprocessor binary, load these files of Scheme code in the normal way.


Ownership, Maintenance and Disclaimers

Manual Top Page

Last modified