From pgilbert@bank-banque-canada.ca  Thu May 14 16:06:11 1998
From: pgilbert@bank-banque-canada.ca (Paul Gilbert)
Date: Thu, 14 May 1998 11:06:11 -0400
Subject: all.equal - cut two, test.equal
Message-ID: <98May14.112616edt.13521@mailgate.bank-banque-canada.ca>

Below is a second cut at all.equal and also a generic function test.equal which
is intended to return a T/F value. The default method uses all.equal, which is
the reason I was looking for all.equal in the first place. Prompted by Thomas
Lumley's observation that a T/F result makes more sense I thought it would be
worthwhile to indicate what I'm really doing.

I have been using test.equal for a few  years in a fairly extensive set of tests
for my time series library. My tests never get to the all.equal part of the
default method, so I have only just noticed the absence of this function. This
approach to testing equality works very well since it allows for a class
specific definition of when things are equal. It was originally suggested to me
by John Chambers, in the context of a question I had about error trapping which,
since I'm on the subject, I will describe shortly in a separate post.

One shortcoming of the following all.equal is that numeric elements of a list
are not compared using tolerance. If anyone has a simple suggestion for
extracting the numeric parts of a list I would like to incorporate it.

Paul Gilbert
_______

test.equal <-function (obj1, obj2, ...)  UseMethod("test.equal")

 test.equal.default <-function (obj1, obj2, ...)
{ if (is.array(obj1))    test.equal.array(obj1, obj2, ...)
   else                         is.logical(all.equal(obj1, obj2, ...))
}

all.equal <- function(obj1, obj2, tolerance=100*Machine()$double.eps)
  {if(mode(obj1)      != mode(obj2) )               return("modes differ.")
   if (length(obj1) != length(obj2) )               return("lengths differ")

   if(is.null(class(obj1)) != is.null(class(obj2))) return("classes differ.")
   else if(!is.null(class(obj1))
           && any(class(obj1) != class(obj2)) )     return("classes differ.")


   if(is.null(attributes(obj1)) != is.null(attributes(obj2)))
                                                    return("attributes differ.")

   else if(!is.null(attributes(obj1))
           && any(unlist(attributes(obj1)) != unlist(attributes(obj2))))
                                                    return("attributes differ.")

   # The mode test above insures that both are numeric if one is. A shortcoming
   # here is that for a list with some numeric components, the components are
   # not compared using the tolerance test.
   if(is.numeric(obj1))
      {if (any(abs(obj1 -obj2) > tolerance))
                               return("value differences exceed tolerance.") }
   else if (! all(unlist(obj1) == unlist(obj2)))     return("values differ.")
   T
  }



-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._


all.equal - cut two, test.equal
Paul Gilbert