[racket] unit test for close enough values
You've got yourself a tricky problem, here.
The accepted way to compare how close two vectors or matrices are is to
compute the norm of their difference - basically, the distance between
them. The functions `matrix-absolute-error' and `matrix-relative-error'
in `math/matrix' do that, and handle +inf.0, +nan.0 entries correctly.
You can use `->col-matrix' to convert vectors to matrices; i.e.
(matrix-relative-error (->col-matrix v1) (->col-matrix v2))
where `v2' is the assumed-correct vector. If this value is less than
1e-15, then (using the default error norm) the worst entry in `v1' has
at least 15 correct digits (sort of). (If less than 1e-14, the worst
entry has at least 14 correct digits, and so on.)
But you have a *set* of vectors. A straightforward way to test this is
this way:
(require math/matrix)
(define (setof-vector=? vs1 vs2 [eps 1e-14])
(let ([vs1 (map ->col-matrix (set->list vs1))]
[vs2 (map ->col-matrix (set->list vs2))])
(for/or ([vs1 (in-list (permutations vs1))])
(for/and ([v1 (in-list vs1)]
[v2 (in-list vs2)])
(< (matrix-relative-error v1 v2) eps)))))
where `v2' is assumed to be the correct set of vectors. So we have
> (setof-vector=? (set #(4 5 6.00000000000001)
#(1 2 3.000000000000004))
(set #(1 2 3)
#(4 5 6)))
#t
> (setof-vector=? (set #(4 5 6.00000000000001)
#(1 2 3.00000000000004))
(set #(1 2 3)
#(4 5 6)))
#f
But we have to ask whether there is a *permutation* of `vs1' elements
which, when matched up with those in `vs2', all have relative error less
than `eps'. That's O(n!) in the number of elements.
There's probably a tricky way to do this efficiently, but I don't know
what it is. You might find one in your problem domain; e.g. there may be
a fast way to test whether a basis is approximately the same as another
basis, particularly if they're each orthogonal.
If you could avoid approximate equality testing on sets, that would be
even better. Without context, it's ambiguous. Even with context, it's
hard to figure out. For example, what should the following test return?
> (setof-vector=? (set #(1.00000000000001 1.00000000000001)
#(0.99999999999999 0.99999999999999))
(set #(1 1)))
Neil ⊥
On 12/21/2013 04:34 PM, J G Cho wrote:
> That looks very useful.
>
>
> On Sat, Dec 21, 2013 at 6:23 PM, Greg Hendershott
> <greghendershott at gmail.com <mailto:greghendershott at gmail.com>> wrote:
>
> > check-= wants single value but unfortunately my values are
> wrapped in set of vectors.
>
> Oh I didn't notice that.
>
> In that case you could define your own check -- that looks inside the
> sets and vectors to do the approximate equality test -- using the
> second variant of `define-binary-check` as described here:
>
> http://docs.racket-lang.org/rackunit/api.html#%28form._%28%28lib._rackunit%2Fmain..rkt%29._define-binary-check%29%29
>
>
>
>
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users
>