/* This file is a part of the Dylp LP distribution. Copyright (C) 2005 -- 2007 Lou Hafer School of Computing Science Simon Fraser University Burnaby, B.C., V5A 1S6, Canada lou@cs.sfu.ca This code is licensed under the terms of the Common Public License (CPL). */ #ifndef _DYLP_VECTOR_H #define _DYLP_VECTOR_H /* @(#)dy_vector.h 4.5 11/06/04 svn/cvs: $Id: dy_vector.h 198 2008-01-03 00:43:36Z lou $ */ #include /* Why, you might ask, are we including ctype.h? Well, it's required by the ANSI C specification, so it's pretty well guaranteed to exist. And, at least in Solaris and Linux environments that I'm familiar with, it'll pull in the compile-time symbols that specify big- or little-endian, which we really want. */ #include /* A bunch of standard definitions. */ #include "dylib_std.h" /* In a few rare instances, the declarations here will be unused, but for dylp this is a good bet. */ #include /* Some subset of these will work on any system. Check config_dylp.h to see which ones are actually in use. */ #ifdef HAVE_FLOAT_H # include #endif #ifdef HAVE_IEEEFP_H # include #endif #ifdef HAVE_SUNMATH_H # include #endif /* The Theory: quiet_nan is used to indicate failure (by returning NaN) without triggering a signal the client may not be prepared to catch. The idea is that any reasonable checks in the client will detect NaN fairly quickly. signalling_nan is used when there's no advantage in delaying a signal. The Reality: Neither seems to trigger a signal, and many computing environments can't tell the difference. But it's coded into dylp, and it'd be much ado to change. Hence the compile-time ugliness that follows. In the Sun Workshop environment, quiet_nan and signalling_nan are declared in sunmath.h and found in libsunmath. With release 5.0, sunmath.h includes some declarations of type `long long', which isn't supported under the -Xc (strict ANSI compatibility) option for cc. So, we extract only the definitions we need. Unfortunately, sunmath.h is present only in the Sun Workshop programming environment. Sun without Workshop has only the require file nan.h, which is inadequate. For a long while, GNU C didn't distinguish QNaN and SNaN. More recently, its support for IEEE 754 seems to have improved, but it's not clear that we can count on everyone having a recent GCC environment just yet. Here, too, nan.h is inadequate. The easy way out is to simply #define them as macros that return the proper bit pattern. Arguably this would make more sense in general than Sun's implementation as functions. According to IEEE 754, the proper bit patterns are: 0x7ff00000 00000000 for Inf 0x7fffffff ffffffff for QNaN 0x7ff00000 00000001 for SNaN It works this way: The IEEE definition of NaN is Bits Value 63 sign --- don't care for a NaN, but nice to be positive (0) 62:52 exponent --- must be maximum value, 0x7ff 51:0 fraction --- must not be zero (a fraction of zero is the representation of infinity). Sun documentation defines QNaN as having bit 51 of the fraction set to 1, SNaN as having bit 51 set to 0. Creating the proper constants qualifies as a serious gross hack. And if you have a little-endian machine (the 80x86 family being far and away the most common example), you need to flip the byte order. */ typedef union { unsigned char fpchr[8] ; double fpdbl ; } fpunion_t ; /* Yes, all this really is needed to get all the various compilers to quit complaining. We need the `(unsigned char)' to prevent some compilers from complaining about the initialiser being out of range. Goes to the ANSI C rule that `Character constants not preceded by the letter L have type int.' */ #ifdef WORDS_BIGENDIAN static fpunion_t QNaNbits UNUSED = { { (unsigned char) '\177', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\376' } } ; static fpunion_t SNaNbits UNUSED = { { (unsigned char) '\177', (unsigned char) '\360', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\001' } } ; static fpunion_t Infbits UNUSED = { { (unsigned char) '\177', (unsigned char) '\360', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0' } } ; #else static fpunion_t QNaNbits UNUSED = { { (unsigned char) '\376', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\377', (unsigned char) '\177' } } ; static fpunion_t SNaNbits UNUSED = { { (unsigned char) '\001', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\360', (unsigned char) '\177' } } ; static fpunion_t Infbits UNUSED = { { (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\0', (unsigned char) '\360', (unsigned char) '\177' } } ; #endif /* WORDS_BIGENDIAN */ /* If we didn't find a quiet_nan function, fake it with a macro. */ #ifndef DYLP_HAS_QUIET_NAN # define quiet_nan(zz_dummy_zz) (QNaNbits.fpdbl) #endif /* On some machines, HUGE_VAL isn't actually IEEE infinity. Make sure that it really is IEEE infinity. */ #undef HUGE_VAL #define HUGE_VAL (Infbits.fpdbl) /* In a Sun/Solaris environment, the definitions and functions that support IEEE floating point are in ieeefp.h. This seems to be true even if GNU compilers are being used instead of Sun Workshop compilers. In a GNU/Linux environment, the necessary definitions seem to live in math.h. The upshot is that we need to explicitly pull in ieeefp.h here for a Sun environment. In a Microsoft environment the correct functions look to be _finite and _isnan from float.h. Assign the proper names to finite and isnan, based on the values deduced by configure. Again, check config_dylp to see the actual names. If either name is already defined, bet that it's the correct definition. */ #ifndef finite # define finite DYLP_ISFINITE #endif #ifndef isnan # define isnan DYLP_ISNAN #endif /* Packed Vectors The packed vector type consists of a header plus an array of pairs for the non-default entries of the vector. pkcoeff_struct Field Description ----- ----------- ndx the column/row index for the coefficient val the value of the coefficient pkvec_struct Field Description ----- ----------- ndx the common index for all coefficients when the vector is a row or column from a matrix nme name associated with this vector, if any dim length of the vector when unpacked dflt the default value of coefficients not in coeffs cnt number of non-default coefficients in the coeffs array sze allocated capacity (in pkcoeff_struct's) of the coeffs array coeffs the array of (column/row index, coefficient) pairs NOTE: pkvec_struct->coeffs is indexed from 0 and sized accordingly. */ typedef struct { int ndx ; double val ; } pkcoeff_struct ; typedef struct { int ndx ; const char *nme ; int dim ; double dflt ; int cnt ; int sze ; pkcoeff_struct *coeffs ; } pkvec_struct ; pkvec_struct *pkvec_new(int sze) ; bool pkvec_resize(pkvec_struct *pkvec, int sze) ; void pkvec_free(pkvec_struct *pkvec) ; bool pkvec_check(pkvec_struct *pkvec, const char *caller) ; double pkvec_2norm(pkvec_struct *vec) ; double exvec_1norm(double *vec, int len), exvec_ssq(double *vec, int len), exvec_2norm(double *vec, int len), exvec_infnorm(double *vec, int len, int *p_jmax) ; double pkvec_dotexvec(pkvec_struct *pkvec, double *exvec) ; #endif /* _DYLP_VECTOR_H */