From: Eric Lavigne
Subject: help debugging function
Date: 
Message-ID: <1114309418.459043.5060@o13g2000cwo.googlegroups.com>
I am having trouble debugging a function. I have included the function
and the beginning of the backtrace. The complete source code is
available on my website: plaza.ufl.edu/lavigne/ and is called
"Diffusion Code 3." I am using clisp and slime (LispBox) on windows xp.

Backtrace line 5 shows that
(NODE-FLUX (AREF RESULT-FLUX I J (1- K)))
was evaluated before
(NODE-FLUX (AREF RESULT-FLUX I J (1+ K)))
but that the latter was the first to cause an error. This suggests that
(i,j,k-1) has a value but (i,j,k+1) does not. Both of these have fewer
odd indices than (i,j,k) and therefore should have been set earlier
(see the dotimes... n... in the function).


SYSTEM::%STRUCTURE-REF: NIL is not a structure of type NODE
   [Condition of type SIMPLE-TYPE-ERROR]
Restarts:
  0: [ABORT] Abort handling SLIME request.
Backtrace:
  0: frame binding variables (~ = dynamically):
  | ~ SYSTEM::*FASOUTPUT-STREAM* <--> NIL
  1: EVAL frame for form (SYSTEM::%STRUCTURE-REF 'NODE SYSTEM::OBJECT
2)
  2: EVAL frame for form (THE T (SYSTEM::%STRUCTURE-REF 'NODE
SYSTEM::OBJECT 2))
  3: APPLY frame for call (NODE-FLUX 'NIL)
  4: EVAL frame for form (NODE-FLUX (AREF RESULT-FLUX I J (1+ K)))
  5: EVAL frame for form (+ (NODE-FLUX (AREF RESULT-FLUX I J (1- K)))
(NODE-FLUX (AREF RESULT-FLUX I J (1+ K))))
  6: EVAL frame for form (* (MATERIAL-V-SIGMA-F MATERIAL) (/ CRIT) 0.5
(+ (NODE-FLUX (AREF RESULT-FLUX I J (1- K))) (NODE-FLUX (AREF
RESULT-FLUX I J (1+ K)))))
...

(defun expand-flux-3d (flux dx material-selector crit)
  ; let result-flux be an array that is twice as long
  ; in each direction as flux
  (let ((result-flux
         (make-array
          (mapcar
           #'(lambda (x) (* 2 x))
           (array-dimensions flux)))))
    ; fill in the gaps based on a 1-D estimate
    ; start with nodes that have the fewest
    ; odd indices to guarantee that there
    ; will be enough flux information
    ; in nearby nodes
    ; n is the number of odd indices, 4 possibilities starting with 0
    (dotimes (n 4)
      (dotimes (i (array-dimension flux 0))
        (dotimes (j (array-dimension flux 1))
          (dotimes (k (array-dimension flux 2))
            (when (eql n (number-odd i j k))
              (let ((material (funcall material-selector i j k)))
                (setf
                 (aref result-flux i j k)
                 (make-node
                  :material material
                  :flux
                  (cond
                    ((oddp i) (phi-1d
                               (aref result-flux (1+ i) j k)
                               (aref result-flux (1- i) j k)

                               (* (material-v-sigma-f material)
                                  (/ crit) 0.5
                                  (+ (node-flux
                                       (aref result-flux (1+ i) j k))
                                     (node-flux
                                       (aref result-flux (1- i) j k))))
                               dx
                               material))
                    ((oddp j) (phi-1d
                               (aref result-flux i (1+ j) k)
                               (aref result-flux i (1- j) k)

                               (* (material-v-sigma-f material)
                                  (/ crit) 0.5
                                  (+ (node-flux
                                       (aref result-flux i (1+ j) k))
                                     (node-flux
                                       (aref result-flux i (1- j) k))))
                               dx
                               material))
                    ((oddp k) (phi-1d
                               (aref result-flux i j (1+ k))
                               (aref result-flux i j (1- k))

                               (* (material-v-sigma-f material)
                                  (/ crit) 0.5
                                  (+ (node-flux
                                       (aref result-flux i j (1- k)))
                                     (node-flux
                                       (aref result-flux i j (1+ k)))))
                               dx
                               material))
                    ; no odd indices? that's the easy case
                    ; just copy the value from flux
                    (t (node-flux
                         (aref flux (/ i 2) (/ j 2) (/ k 2)))))))))))))
    result-flux))

The input "flux" was an array of nodes.
The input I used at the terminal was...

(setf my-material (make-material :D .9 :v-sigma-f .07 :sigma-a .066))
(setf flux (make-array '(20 20 20)))
(dotimes (i (array-dimension flux 0))
 (dotimes (j (array-dimension flux 1))
  (dotimes (k (array-dimension flux 2))
   (setf (aref flux i j k)
         (make-node :flux 1 :material my-material)))))
(expand-flux-3d flux .2 #'simple-material-selector .1)

From: Alan Crowe
Subject: Re: help debugging function
Date: 
Message-ID: <861x90bbhh.fsf@cawtech.freeserve.co.uk>
Eric Lavigne wrote

                    ((oddp i) (phi-1d
                               (aref result-flux (1+ i) j k)
                               (aref result-flux (1- i) j k)

Eric, you are trying to expand (0 1 2) to (0 1 2 3 4 5)
and use interpolation to fill in the gaps

     0   1   2
     0 1 2 3 4 5
       ^
       |
       `-- interpolated between 0 and 1

But what is to happen with 5? So I think the bug is right at
the start with

        (make-array
          (mapcar
           #'(lambda (x) (* 2 x))
           (array-dimensions flux)))))

Surely you need #'(lambda (x)(- (* 2 x) 1))
or some means of extrapolation.

I am most impressed by your ingenuity. The way you generate
the intricate sequence of references by four sweeps that
filter on the sweep number is very clever.

However you are missing a very useful trick for organising
your code to make it easy to debug. Write a function that
just does the sequencing, but has no 'guts'. Give it its
guts by passing in a functional argument. Then, before
trying it out for real, test it by passing functional
arguments that simply report back to you, the programmer.

In your final pass you filter out 7/8's of the points.
You might try writing code to generate only the points you
want, something like this.

(defun fill-array-using-offsets (array func offset-i offset-j offset-k)
    (loop for i
	  from offset-i
	  below (array-dimension array 0)
	  by 2
	  do (loop for j
		   from offset-j
		   below (array-dimension array 1)
		   by 2
		   do (loop for k
			    from offset-k
			    below (array-dimension array 2)
			    by 2
			    do (setf (aref array i j k)
				     (funcall func i j k)))))
    array)

(fill-array-using-offsets (make-array '(3 3 3))
			    #'list
			    1 1 1)
=>
#3A(((0 0 0) (0 0 0) (0 0 0))
    ((0 0 0) (0 (1 1 1) 0) (0 0 0))
    ((0 0 0) (0 0 0) (0 0 0)))

(defun sequence-interpolation (array func)
    (dolist (offsets '((0 0 1)
		       (0 1 0)
		       (1 0 0)
		       (1 1 0)
		       (1 0 1)
		       (0 1 1)
		       (1 1 1))
		     array)
      (apply #'fill-array-using-offsets array func offsets)))

(sequence-interpolation (make-array '(3 3 3))
			  #'list)
=>
#3A(((0 (0 0 1) 0) ((0 1 0) (0 1 1) (0 1 2)) (0 (0 2 1) 0))
    (((1 0 0) (1 0 1) (1 0 2))
     ((1 1 0) (1 1 1) (1 1 2))
     ((1 2 0) (1 2 1) (1 2 2)))
    ((0 (2 0 1) 0) ((2 1 0) (2 1 1) (2 1 2)) (0 (2 2 1) 0)))

(sequence-interpolation (make-array '(3 3 3))
			  (let ((count 0))
			    (lambda (i j k)
			      (print (list i j k))
			      (incf count))))

(0 0 1) 
(0 2 1) 
(2 0 1) 
(2 2 1) 
(0 1 0) 
(0 1 2) 
(2 1 0) 
(2 1 2) 
(1 0 0) 
(1 0 2) 
(1 2 0) 
(1 2 2) 
(1 1 0) 
(1 1 2) 
(1 0 1) 
(1 2 1) 
(0 1 1) 
(2 1 1) 
(1 1 1) 
#3A(((0 1 0) (5 17 6) (0 2 0))
    ((9 15 10) (13 19 14) (11 16 12))
    ((0 3 0) (7 18 8) (0 4 0)))

This last example might be rather shocking.
The form

(let ((count 0))
  (lambda (i j k)
    (print (list i j k))
    (incf count))

evaluates to a function, indeed a closure, with its own
private variable called count, which it increments on every
call. Using it to fill the array results in an array that
shows you the sequence in which it was filled, see number 19
right in the middle at 1,1,1.

I hope I don't frighten you off Lisp with my strange Lispy
code.

Alan Crowe
Edinburgh
Scotland
From: Eric Lavigne
Subject: Re: help debugging function
Date: 
Message-ID: <1114350369.181235.180330@l41g2000cwc.googlegroups.com>
>Eric, you are trying to expand (0 1 2) to (0 1 2 3 4 5)
>and use interpolation to fill in the gaps
>
>     0   1   2
>     0 1 2 3 4 5
>       ^
>       |
>       `-- interpolated between 0 and 1
>
>But what is to happen with 5?

There's a 5? Wow, that was unexpected.

>Surely you need #'(lambda (x)(- (* 2 x) 1))
>or ...

That did it :-)

>I hope I don't frighten you off Lisp with my
>strange Lispy code.

"That's either very cool or very scary depending on your point of
view."
Peter Seibel
Practical Common Lisp - chapter 3

I've found that a lot of Lisp is like that. Your code is a bit scary,
but give me a few days and I'll get used to it.

Now for the next error message...
+: 1.0140682 is not a NUMBER
   [Condition of type SIMPLE-TYPE-ERROR]

Most people would have a hard time saying that with a straight face,
but my interpreter says it with such authority. Actually, I know what
this means, but I just thought it was funny. My nodes look like numbers
when printed (showing just the value of flux). Thanks for the help,
Alan.
From: Pascal Bourguignon
Subject: Re: help debugging function
Date: 
Message-ID: <87oec4uw79.fsf@thalassa.informatimago.com>
"Eric Lavigne" <············@gmail.com> writes:
>
> Now for the next error message...
> +: 1.0140682 is not a NUMBER
>    [Condition of type SIMPLE-TYPE-ERROR]
>
> Most people would have a hard time saying that with a straight face,
> but my interpreter says it with such authority. Actually, I know what
> this means, but I just thought it was funny. My nodes look like numbers
> when printed (showing just the value of flux). Thanks for the help,
> Alan.

You might want to use PRINT-UNREADABLE-OBJECT.

-- 
__Pascal_Bourguignon__               _  Software patents are endangering
()  ASCII ribbon against html email (o_ the computer industry all around
/\  1962:DO20I=1.100                //\ the world http://lpf.ai.mit.edu/
    2001:my($f)=`fortune`;          V_/   http://petition.eurolinux.org/