OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

 


 

   Re: An approach to describing the relationships betweenunits-of-measure

[ Lists Home | Date Index | Thread Index ]


costello@mitre.org@INTERNET@wtgw'(Roger L. Costello):
| EXAMPLE 1
| 
| To explain the approach I will use this example:
| 
|    <River id="Yangtze">
|         <length>
|             <kilometer>6340</kilometer>
|         </length>
|    </River>
| 
| Recall that <kilometer> may be considered as a function:
... 
|     kilometer(Distance) --> number

I'd say that more usually kilometre is considered a function that maps a number to 
a distance. If you consider the canonical distance to be a metre, you can define:
  (defun kilometre (x) (uom-* 1000 (metre x)))
; where
  (defun uom-* (scalar uom) (list (car uom) (* scalar (cadr uom))))
  (defun metre (x) (distance x))
  (defun distance (x) (list 'distance x))

I don't do MathML, so you'll have to make do with lisp as it's a convenient 
functional language.

I prefer that the kilometre function adds information to a number making it a 
distance, instead of removing information.

<River id="Yangtze">
         <length>
             <kilometer>6340</kilometer>
         </length>
    </River>
-->
(defclass River () ((id :initarg :id :accessor :id) (length :initarg :length :
accessor :length))) 
(defmacro River (&rest r) (apply 'make-instance 'River r)) 

(River :id Yangtze :length (kilometre 6340))
  => #<RIVER>

| Likewise, for this version:
| 
|    <River id="Yangtze">
|         <length>
|             <mile>3914</mile>
|         </length>
|    </River>
| 
| mile is a function that maps a Distance to a number:
| 
|     mile(length(Yangtze)) --> 3914
| 
| or more generally:
| 
|     mile(Distance) --> number

alternatively 
     (defun mile (x) (uom-* 5280 (foot x))) 
     (defun foot (x) (uom-* 12 (inch x))) 
     (defun inch (x) (uom-* 0.0254 (metre x)))

; or in prefix notation:
;    mile(number) => 5286 * foot (number) = 63360 * inch (number)
;                 = 1609.35 * metre (number)

so
 <River id="Yangtze">
         <length>
             <mile>3914</mile>
         </length>
    </River>
-->
(River :id Yangtze :length (mile 3914))
  => #<RIVER>

| "Those instances that represent equivalent Distances are 
| the set of k (kilometer), m (mile) pairs such that k = m * 1.62"

Are the length properties of two rivers the same? 

(setf yang-0 (River :id Yangtze :length (kilometre 6299)))
(setf yang-1 (River :id Yangtze :length (mile 3914)))

(:length yang-0) => (kilometre 6299)
(eval (:length yang-0)) => (DISTANCE 6299000)

; equivalent-uom-value tests the evaluated form of two lists 
; and compares the numeric values in the second member each the 
; list, using the second member of the tolerance list as a absolute
; tolerance if present. If the dimensions of the values are not
; equal it will return false.
(defun equivalent-uom-value (x y &optional &key (tolerance nil))
  (let ((x (eval x)) (y (eval y)) (tolerance (eval tolerance)))
     (if (and tolerance (numberp (cadr x)) (numberp (cadr y)))
        (and (> (+ (cadr x) (cadr tolerance)) (cadr y) (- (cadr x) (cadr 
tolerance)))
          (equal (car x) (car y))
          (equal (car x) (car tolerance)))
        (equal x y))))
 => EQUIVALENT-UOM-VALUE

(equivalent-uom-value (:length yang-0) (:length yang-1))
 => NIL

(equivalent-uom-value (:length yang-0) (:length yang-1) :tolerance (metre 30)) 
 =>T

; degrees and radians
(defun degree (x) (uom-* (/ pi 180) (radian x)))
(defun radian (x) (angle x))
(defun angle (x) (list 'angle x))

(equivalent-uom-value (metre 7) (radian 7)) => NIL

Implicitly an equivalence relation defines a set. 

| For example, (6340 k, 3914 m) represent equivalent Distances.

BTW 
 (equivalent-uom-value (mile 3914) (kilometre 6340) :tolerance (kilometre 40)) => 
NIL
wheres
 (equivalent-uom-value (mile 3914) (kilometre 6299) :tolerance (foot 100)) => T 

So I guess that either kilometres are subject to an import duty on entering the USA,
 or your mile isn't a statue mile ;).
 
| I envision a document containing class definitions (e.g.,
| the Distance class). I envision an API to enable programs to
| programmatically access the class info via the API.

I've done similar to the above, but with functions that convert numbers to 
distances rather than distances to numbers in a several hundred lines of Java, with 
XML data files like:
  <Blah
    length = "2.134"
    length_units = "km"
  />

The syntax of which is mainly due to XMI->Java mapping limitations. 

| This API may have a method such as this:
| 
|      boolean isContainedIn((uom1_value, uom2_value), set);
| 
| The method, isContainedIn, has two arguments. The first argument 
| contains a pair of unit-of-measure values, and the second argument 
| is a set definition.  The result is a boolean.

What would be the truth table of this method? If the set is the set of equivalent 
uom_values, then it's infinite and exposing it as the api has no more functionality 
than exposing the function equivalent-uom-value.

| <Class id="Distance">
|     <equivalentInstances>
|         {k, m | k = m * 1.62}expressed as MathML
|         {k, m | k = m * 1.62}expressed as Mathematica
|         {k, m | k = m * 1.62}expressed as xPath(???)
|     </equivalentInstances>
| </Class>

Do you really want to define units^2*representations functions, or wouldn't it be 
better to define one function for each units (in whatever representation) that 
generates a canonical form for the equivalence realtion?
 
| Do you have suggestions on how to represent tolerance?

- fixed, as a uom-value, eg  the example I gave above
- relative to one of the input values
 
| EXAMPLE 2
...
| Here is the completed Location class:
| 
| <Class id="Location>
|     <equivalentInstances>
|         {c, p | c.x.kilometer = p.r.kilometer sin p.theta.radian ^ 
|                      c.y.kilometer = p.r.kilometer cos p.theta.radian}
|     </equivalentInstances>
| </Class>
| 
| Note: I am not convinced that this is the best way to express the set.
| Do you have any suggestions?

I'd call it coordianate-2d or something; a general location needs 3D [+ time stamp] 
[+ tolerance/confidence], a co-ordinate system and possibly a reference point (eg: 
lat/long/alititude the reference point is implied but inertial systems 
distance-north/distance-east/distance-down the reference point is also required)

Unfortunately, there isn't a single canonical form for equivalence:
 if p0 is a cartesian point with a tolerance t0 of +/- x metres in any direction 
 and p1 a polar point with a tolerance t1 of +/- y degrees and +/- z range
  (equivalent-location (to-polar p0) p1 t1)
 <=/=>
  (equivalent-location p0 (to-cartesian p1) t0) 
 though it should be the case, subject to rounding errors, that
  (equivalent-uom-value (distance-between (to-polar p0) p1) (metre 0) :tolerance 
(metre some-tolerance)) 
 <==>
  (equivalent-uom-value (distance-between p0 (to-cartesian p1)) (metre 0) :
tolerance (metre some-tolerance)) 

| API  REVISITED
| 
| Recall the API that was mentioned above:
| 
|     boolean isContainedIn((uom1_value, uom2_value), set, tolerance);
| 
| Recall that "tolerance" is used to indicate how much slack you 
| are willing to accept in deciding if a pair of values are contained 
| in the set.  In this Map example the tolerance is effectively a 
| way of indicating "I want all values within this region".  When 
| you tighten the tolerance, you narrow the region.  When you loosen 
| the tolerance, you widen the region. I think this will be very useful.
 
In this case tolerance then would consist of a function to covert uom1_value and 
uom2_value to a common form, a function to compute the difference in some form, and 
a value that the difference value have to be less than.

For the length case, the common form is the canonical form SI metres; for the 
location case different tolerances (cartesian-tolerance, polar-tolerance, 
distance-tolerance) would require different common forms and difference 
computations.
eg:
  (equivalent-location p0 p1 (polar-tolerance :theta (degrees 10) :r (kilometres 
50)))
would test if p0 and p1 have bearings within ten degrees of each other and ranges 
within 50km of each other from an implied origin
  (equivalent-location p0 p1 (distance-tolerance (foot 10)))
would test if p0 and p1 are within 10 feet of each other

As a quick-hacK:
; super class for 2d coordianate. serves no real purpose 
(defclass coordianate-2d () ())
; cartesian location and constructor method
(defclass cartesian-coordinate (coordianate-2d) ((x :initarg :x) (y :initarg :y)))
(defun cartesian-coordinate (&key x y) (make-instance 'cartesian-coordinate :x x :y 
y))

; polar location and constructor method
(defclass polar-coordinate (coordianate-2d) ((r :initarg :r) (theta :initarg :
theta)))
(defun polar-coordinate (&key theta r) (make-instance 'polar-coordinate :theta 
theta :r r))

;<Map id="M21">
;    <location>
;        <polar-coordinate>
;            <r>
;                <kilometer>141.421</kilometer>
;            </r>
;            <theta>
;                <radian>0.7841</radian>
;            </theta>
;        </polar-coordinate>
;    </location>
;</Map>

(defclass Map () ((location :initarg :location :accessor :location)))
(defmacro Map- (&rest r) (apply 'make-instance 'Map r)) 

(setf m (Map- :location (polar-coordinate :r (kilometer 141.421) :theta (radian 0.
7841)))) => #<Map?>

(:location m) => (POLAR-COORDINATE :R (KILOMETER 141.421) :THETA (RADIAN 0.7841))

(defmethod to-cartesian ((pt cartesian-coordinate)) pt)
(defmethod to-cartesian ((pt polar-coordinate)) 
  (let
    ( (r (eval (:r pt))) 
      (theta (eval (:theta pt))))
    (if (and (eql 'distance (car r)) (eql 'angle (car theta)))
      (make-instance 'cartesian-coordinate 
        :x (distance (* (cadr r) (cos (cadr theta)))) 
        :y (distance (* (cadr r) (sin (cadr theta))))))))

(defmethod to-polar ((pt cartesian-coordinate)) 
  (let
    ( (x (eval (:x pt)))
      (y (eval (:y pt))))
    (if (and (eql 'distance (car x)) (eql 'distance (car y)))
      (make-instance 'polar-coordinate 
        :r (distance (sqrt (+ (* (cadr x) (cadr x)) (* (cadr y) (cadr y))))) 
        :theta (angle (atan2 (cadr x) (cadr y)))))))
(defmethod to-polar ((x polar-coordinate)) x) 

; haven't bothered with checking type of x and y 
(defun distance-between (p0 p1) (let ((p0 (to-cartesian p0)) (p1 (to-cartesian 
p1)))
 (let
  ( (dx (- (cadr (:x p0)) (cadr (:x p1))))
    (dy (- (cadr (:y p0)) (cadr (:y p1)))))
  (distance (sqrt (+ (* dx dx) (* dy dy)))))))

; create a comparison with based on an absolute tolerance
(defun distance-tolerance (tolerance)
  (lambda (p0 p1) 
    (equivalent-uom-value (distance-between p0 p1) (distance 0) :tolerance 
tolerance)))

; do something similar for polar-tolerance- creates an appropriate comparitor 
function 
; by converting p0 and p1 to polar and taking the difference 
; (defun polar-tolerance (&key r-tolerance theta-tolerance) ...

; the equivalence function for locations
(defun equivalent-location (p1 p2 &optional &key (tolerance (distance-tolerance 
(metre 1))))
  (funcall tolerance p1 p2))
; default tolerance is 1 metre

(setf *WARN-ON-FLOATING-POINT-CONTAGION* nil)
; it's quite contagious

(setf p0 (polar-coordinate :theta '(degree 90) :r '(metre 1609)))
(setf p1 (cartesian-coordinate :x (mile 0) :y (mile 1)))
 
(equivalent-location p0 p1) => T
(equivalent-location p0 p1 :tolerance (distance-tolerance (metre 10)))  => T
(equivalent-location p0 p1 :tolerance (distance-tolerance (metre 0.01)))  => NIL

(setf p2 (cartesian-coordinate :x (mile 20) :y (mile 0)))

(equivalent-location p0 p2) => NIL
(equivalent-location p0 p2 :tolerance (distance-tolerance (kilometre 40))) => T

; but comparing two values with tolerances isn't a strict equivalence relation
; as it's not always transitive
(setf p0 (cartesian-coordinate :x (metre 1.1) :y (metre 0)))
(setf p1 (cartesian-coordinate :x (metre 2) :y (metre 0)))
(setf p2 (cartesian-coordinate :x (metre 2.9) :y (metre 0)))

(equivalent-location p0 p1) => T
(equivalent-location p1 p2) => T
(equivalent-location p0 p2) => NIL

I'd guess there's similar constructs in the languages you're using.

Pete

********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************




 

News | XML in Industry | Calendar | XML Registry
Marketplace | Resources | MyXML.org | Sponsors | Privacy Statement

Copyright 2001 XML.org. This site is hosted by OASIS