Hi, I have write a function that can calculate the distance between two pts
for 3-dimension. How can I extend it to n-dimension which can take as input
n and 2 lists?
(defun dist (p q)
(setf a (expt (- (first p) (first q)) 2)
b (expt (- (second p) (second q)) 2)
c (expt (- (third p) (third q)) 2))
(format t "~%(Distance)=")
(list (sqrt (+ a b c))))
"Wayne" <··@ecn.purdue.edu> writes:
> Hi, I have write a function that can calculate the distance between two pts
> for 3-dimension. How can I extend it to n-dimension which can take as input
> n and 2 lists?
>
> (defun dist (p q)
> (setf a (expt (- (first p) (first q)) 2)
> b (expt (- (second p) (second q)) 2)
> c (expt (- (third p) (third q)) 2))
> (format t "~%(Distance)=")
> (list (sqrt (+ a b c))))
Here is one (inefficient) way, which resembles your solution somewhat:
(defun dist (p q)
(format t "~%(Distance)=")
(list (sqrt (apply #'+ (mapcar #'(lambda (a b) (expt (- a b) 2)) p q)))))
--
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."
In article <··············@pc022.xcs.local>, Nils Goesche
<············@anylinx.de> wrote:
> "Wayne" <··@ecn.purdue.edu> writes:
>
> > Hi, I have write a function that can calculate the distance between two pts
> > for 3-dimension. How can I extend it to n-dimension which can take as input
> > n and 2 lists?
> >
> > (defun dist (p q)
> > (setf a (expt (- (first p) (first q)) 2)
> > b (expt (- (second p) (second q)) 2)
> > c (expt (- (third p) (third q)) 2))
> > (format t "~%(Distance)=")
> > (list (sqrt (+ a b c))))
>
> Here is one (inefficient) way, which resembles your solution somewhat:
>
> (defun dist (p q)
> (format t "~%(Distance)=")
> (list (sqrt (apply #'+ (mapcar #'(lambda (a b) (expt (- a b) 2)) p q)))))
a) In general don't use APPLY for this. REDUCE is safer
(because: arglist length limit).
b) Format does output.
But, you don't have a print statement for the second
form. It just might happen that a toplevel loop
prints it - or not.
c) Why have an extra LIST call?
d) Style: don't mix output and computation.
Write an extra form.
--
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
how about a list of lists pass the list in which contains the n set of lists
then change your setf statement so that it is a more general equation. then
just go throw the list applying your more generic algorithm, very similar to
what you have now but less structured and specialized to handling only two
list.
(list (sublist one)
(sublist two)
(sublist two)
(ect))
(defun dist (a)
(loop until all sublists are completed.)
get sub list
(setf ect
(end loop)
)
Wayne wrote:
> Hi, I have write a function that can calculate the distance between two pts
> for 3-dimension. How can I extend it to n-dimension which can take as input
> n and 2 lists?
>
> (defun dist (p q)
> (setf a (expt (- (first p) (first q)) 2)
> b (expt (- (second p) (second q)) 2)
> c (expt (- (third p) (third q)) 2))
> (format t "~%(Distance)=")
> (list (sqrt (+ a b c))))
"Wayne" <··@ecn.purdue.edu> writes:
> Hi, I have write a function that can calculate the distance between
> two pts for 3-dimension. How can I extend it to n-dimension which
> can take as input n and 2 lists?
(defun dist (v1 v2)
"Find the distance between to points in euclidean N-space
represented by lists (of numbers) V1 and V2 of length N."
(sqrt (loop for a in v1 and b in v2
summing (expt (- a b) 2))))
You can of course chose to pass along N explicitly and emit an error
if the actual length of the vector-lists differs from N, but in
general that doesn't seem to me to be very useful.
--
Frode Vatvedt Fjeld
> "Wayne" <··@ecn.purdue.edu> writes:
>> Hi, I have write a function that can calculate the distance between
>> two pts for 3-dimension. How can I extend it to n-dimension which
>> can take as input n and 2 lists?
Be sure you talk about the right distance: there are a number of useful
distance measures. E.g. Euclidean (the usual suspect), City Block,
generalized Minkovski etc. To keep things general, you could put the
Minkovski exponent k (or whatever it's called) as an argument:
(defun minkovski-dist (v1 v2 &optional k)
(let ((k (or k 2))) ; defaults to Euclidean
(expt (loop for a in v1 and b in v2
summing (expt (abs (- a b)) k)) (/ 1.0 k))))
using k == 1 you have the cityblock distance (ok this is slow).
To make it even more general you can even put a functional argument in the
distance function, but I guess you'll have to use two arguments: one function
for the per-dimension difference during the summing (e.g. squaring the
difference in case of Euclidean dist.), and one for reducing dimensions of
the summed distances back to 1 (e.g. taking square root in case of Euclidean
distances). Or is there a way to achieve this using one functional argument ?
Cheers,
Philip
--
When C++ is your hammer, everything looks like a thumb. (Steven Haflich)
-----------------------------------------------------------------------------
Philip Lijnzaad, ········@ebi.ac.uk \ European Bioinformatics Institute,rm A2-24
+44 (0)1223 49 4639 / Wellcome Trust Genome Campus, Hinxton
+44 (0)1223 49 4468 (fax) \ Cambridgeshire CB10 1SD, GREAT BRITAIN
PGP fingerprint: E1 03 BF 80 94 61 B6 FC 50 3D 1F 64 40 75 FB 53
Thanks! But is it possible to write a function which can take input
n and 2 lists? as follow, ( I have to learn how to use "do".)
Does the error occur at "setf.."? Can it be written to a function that I
want to call this in other function?
(print '(Please type the number of dimension))
(setf n (read))
(print '(Please type the coordinate of 1st point))
(setf v1 (read))
(print '(Please type the coordinate of 2nd point))
(setf v2 (read))
(setf r (sqrt (do ((r 0 (+ (expt (- (first v1) (first v2)) 2) r))
(setf v1 (rest v1))
(setf v2 (rest v2)))
((endp v1) result)))
(format t "~%(Distance)=")
(print (list r))
(PLEASE TYPE THE NUMBER OF DIMENSION)3
(PLEASE TYPE THE COORDINATE OF 1ST POINT)(1 2 1)
(PLEASE TYPE THE COORDINATE OF 2ND POINT)(2 4 5)
Error: eof encountered on stream
#<EXCL::CHARACTER-INPUT-FILE-STREAM
#p"D:\\app\\TOOLS\\acl501lite\\temp.cl" pos 459 @ #x204cde42>
[condition type: END-OF-FILE]
I just got it! But how can I write it to be a function that I
can call this from other function? The "command" like other BASIC's
"Subroutine()" and "CALL".
(print '(Please type the number of dimension))
(setf n (read))
(print '(Please type the coordinate of 1st point))
(setf v1 (read))
(print '(Please type the coordinate of 2nd point))
(setf v2 (read))
(setf r (sqrt (do ((r 0 (+ (expt (- (first v1) (first v2)) 2) r))
(v1 v1 (rest v1))
(v2 v2 (rest v2)))
((endp v1) r))))
(format t "~%(Distance)=")
(print (list r))
"Wayne" <··@ecn.purdue.edu> wrote in message
·················@mozo.cc.purdue.edu...
> I just got it! But how can I write it to be a function that I
> can call this from other function? The "command" like other BASIC's
> "Subroutine()" and "CALL".
Look at the documentation for the macro "defun" (short for deFINE funCTION).
faa
"Wayne" <··@ecn.purdue.edu> writes [reformatted]:
> (defun wc (x)
> (do ((result 0 (+ (first x) result))
> (setf x (rest x))) [ <=== not what you think ]
> ((endp x) result)))
> [...]
> I have to learn how to use "do".
> [...]
> (setf r (sqrt (do ((r 0 (+ (expt (- (first v1) (first v2)) 2) r))
> (setf v1 (rest v1)) [ <=== not what you think ]
> (setf v2 (rest v2))) [ <=== not what you think ]
By reformatting your #'do invocations into the standard prettyprint
and lining up corresponding elements, I hope I've made it easier
to see what's wrong. The first argument to #'do is a list of
3-element lists. These are the 3 elements:
[1] <clue>THE NAME OF A VARIABLE</clue>
[2] a form to be evaluated to get the first value of the variable
[3] a form to be evaluated to get each subsequent value of the variable
In each of your #'do invocations, your first 3-element list was coded
correctly, but your subsequent lists were coded as if they were
single Lisp forms to be evaluated. That is the error; they're not
single forms, they're lists containing an unevaluated symbol followed
by two forms that will be evaluated at specific times.
Lisp allows functions and variables to have the same name; for
example, if you enter
(setq sqrt 4)
you've defined a *variable* named "sqrt", but the function #'sqrt
is still available, so you can then enter
(sqrt sqrt)
and get back a result of 2; the first "sqrt" names the function
(because it's the first element of a list that is a single Lisp form
to be evaluated), whereas the second "sqrt" names the variable
(because it's a non-initial element of a list that is a single Lisp form
to be evaluated).
So, what you're doing in both your #'do invocations in your
3-element lists other than the first one is *defining* a *variable*
named "setf", when you thought you were *invoking* the *function*
named "setf". In the case of #'wc, the variable named "setf" is
initially assigned a value equal to all of x, and on all
subsequent iterations is assigned a value equal to all but the
first element of x; but x itself is *never modified*, so the
function goes into an endless loop. For example, the first time
around, x is '(1 2 3 4 5); the second time, it's '(2 3 4 5); the
third time, it's *still* '(2 3 4 5); and so on forever.
This is the simplest change to #'wc that will make it work correctly:
(defun wc (x)
(do ((result 0 (+ (first x) result))
(x x (rest x)))
((endp x) result)))
In the 3-element list '(x x (rest x)), I'm saying that the variable
x will start out as, well, x, then on each subsequent iteration
will become (rest x). This was your original intent.
Hope this helps. Happy hacking.
Will Mengarini <······@eskimo.com>
Free software: the Source will be with you, always.
From: Barry Margolin
Subject: Referring to #'<function> in text (was Re: Distance between two pts)
Date:
Message-ID: <%f9w5.12$ge7.918@burlma1-snr2>
In article <············@eskinews.eskimo.com>,
Will Mengarini <······@eskimo.com> wrote:
>By reformatting your #'do invocations into the standard prettyprint
I've always found it annoying when posters write #'<function> and '<symbol>
in prose like this. But I've never said anything before, because I can
kind of understand why they're doing it -- they're using them in the same
way that they would refer to them in Lisp code.
But the above case really struck me. DO isn't a function, it's a macro, so
if you were to write #'do in Lisp code it would be wrong. So why do you
write it like that in your text? If you want to mimic Lisp, you should
write:
By reformatting your (macro-function 'do) invocations....
It's not as nice looking, but that's because there's no reader-macro
shorthand for MACRO-FUNCTION, like there are for FUNCTION and QUOTE.
--
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
"Wayne" <··@ecn.purdue.edu> writes:
> Thanks! But is it possible to write a function which can take input
> n and 2 lists?
Yes, but why would you want to do that? The only thing you can use n
for, is to make an assertion (= n (length v1) (length v2)). But in
real applications such inconsistencies are unlikely to occur, and
anyways I'd say it would be good form to put such checks somewhere
else than in the core dot product function.
> ( I have to learn how to use "do".)
When it comes to iteration constructs, I pretty much think of DO as
the last resort when all else fails. I'd adivse you to learn DOLIST,
DOTIMES and LOOP first.
> the error occur at "setf.."? Can it be written to a function that I
> want to call this in other function?
The error occurs because your form (setf r (sqrt ... )) lacks one
closing paren. If you use an editor with support for editing lisp, you
will catch such errors easily.
> (print '(Please type the number of dimension))
Why print text as lists of symbols? It looks very strange. Make it
(format t "Please ...")
> (setf n (read))
> (print '(Please type the coordinate of 1st point))
> (setf v1 (read))
> (print '(Please type the coordinate of 2nd point))
> (setf v2 (read))
Lisp supports very well a concept called "functional programming",
which can be a great aid in structuring programs. You should look into
it.
Here is my suggestion for a program that does what I assume you want
to do:
(defun prompt (prompt)
(princ prompt)
(read))
(defun get-two-vectors ()
(let ((n (prompt "Dimensions: "))
(v1 (prompt "First vector: "))
(v2 (prompt "Second vector: ")))
(check-type n (integer 1 *))
(check-type v1 list)
(check-type v2 list)
(assert (= n (length v1) (length v2))
(n v1 v2)
"V1 and V2 must be lists of length ~A." n)
(values v1 v2))) ; return v1 and v2.
(defun dist (v1 v2)
"Find the distance between to points in euclidean N-space
represented by lists (of numbers) V1 and V2 of length N."
(sqrt (loop for a in v1 and b in v2
summing (expt (- a b) 2))))
Now you can do this:
? (multiple-value-bind (v1 v2)
(get-two-vectors)
(format t "Distance: ~A.~%" (dist v1 v2)))
Dimensions: 2
First vector: (2 1)
Second vector: (1 2)
Distance: 1.4142135.
--
Frode Vatvedt Fjeld
In article <··············@dslab7.cs.uit.no>, Frode Vatvedt Fjeld
<······@acm.org> wrote:
> Now you can do this:
>
> ? (multiple-value-bind (v1 v2)
> (get-two-vectors)
> (format t "Distance: ~A.~%" (dist v1 v2)))
I wonder if this would be more efficient:
(format t "Distance: ~A.~%"
(multiple-value-call #'dist (get-two-vectors)))
--
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
Philip Lijnzaad <········@ebi.ac.uk> writes:
> Be sure you talk about the right distance: there are a number of useful
> distance measures. E.g. Euclidean (the usual suspect), City Block,
> generalized Minkovski etc. To keep things general, you could put the
I think you mean Lebesgue as in L^p space. Minkovski has to do with
subtracting some dimensions, as in the Minkovski metric for special
relativity: x^2+y^2+z^2-t^2.
> Minkovski exponent k (or whatever it's called) as an argument:
>
> (defun minkovski-dist (v1 v2 &optional k)
> (let ((k (or k 2))) ; defaults to Euclidean
> (expt (loop for a in v1 and b in v2
> summing (expt (abs (- a b)) k)) (/ 1.0 k))))
>
For L^p you'd have to take the inverse expt over the sum:
(expt (reduce #'+ (mapcar #'(lambda (x y) (expt (abs (- x y)) p)) v1 v2)) (/ p))
for p>=1. For 0<p<1 you get Hardy spaces, which are a different case
altogether.
> using k == 1 you have the cityblock distance (ok this is slow).
>
--
Lieven Marchand <···@bewoner.dma.be>
Lambda calculus - Call us a mad club