Graphite Version 3
An experimental 3D geometry processing program
Loading...
Searching...
No Matches
interval_nt.h
1/*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40#ifndef GEO_INTERVAL_NT
41#define GEO_INTERVAL_NT
42
44#include <geogram/basic/vechg.h>
45#include <iomanip>
46#include <limits>
47#include <cmath>
48
49#ifdef __SSE__
50#include <xmmintrin.h>
51#else
52#include <fenv.h>
53#endif
54
55// Uncomment to activate checks (keeps an arbitrary precision
56// representation of the number and checks that the interval
57// contains it).
58// #define INTERVAL_CHECK
59
60// Uncomment to deactivate all interval filters in geogram
61// (used for debugging and performance tests)
62// #define GEO_NO_INTERVALS
63
64namespace GEO {
65
75 public:
76
77 static void set_FPU_round_to_nearest() {
78#ifdef __SSE__
79 _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);
80#else
81 fesetround(FE_TONEAREST);
82#endif
83 }
84
85 static void set_FPU_round_to_upper() {
86#ifdef __SSE__
87 _MM_SET_ROUNDING_MODE(_MM_ROUND_UP);
88#else
89 fesetround(FE_UPWARD);
90#endif
91 }
92
93 enum Sign2 {
94 SIGN2_ERROR = -1,
95 SIGN2_ZERO = 0,
96 SIGN2_NP,
97 SIGN2_PP,
98 SIGN2_ZP,
99 SIGN2_NN,
100 SIGN2_NZ
101 };
102
103 static bool sign_is_determined(Sign2 s) {
104 return
105 s == SIGN2_ZERO ||
106 s == SIGN2_NN ||
107 s == SIGN2_PP ;
108 }
109
110 static bool sign_is_non_zero(Sign2 s) {
111 return
112 s == SIGN2_NN ||
113 s == SIGN2_PP ;
114 }
115
116 static Sign convert_sign(Sign2 s) {
117 geo_assert(sign_is_determined(s));
118 if(s == SIGN2_NN) {
119 return NEGATIVE;
120 }
121 if(s == SIGN2_PP) {
122 return POSITIVE;
123 }
124 return ZERO;
125 }
126
127 intervalBase() {
128 control_set(0);
129 }
130
131 intervalBase(double x) {
132 control_set(x);
133 }
134
135 intervalBase(const intervalBase& rhs) = default;
136
137 intervalBase& operator=(const intervalBase& rhs) = default;
138
139 protected:
140#ifdef INTERVAL_CHECK
141 void control_set(const expansion_nt& x) {
142 control_ = x;
143 }
144 void control_set(const intervalBase& x) {
145 control_ = x.control_;
146 }
147 void control_set(double x) {
148 control_ = expansion_nt(x);
149 }
150 void control_negate() {
151 control_.rep().negate();
152 }
153 void control_add(const intervalBase& x) {
154 control_ += x.control_;
155 }
156 void control_sub(const intervalBase& x) {
157 control_ -= x.control_;
158 }
159 void control_mul(const intervalBase& x) {
160 control_ *= x.control_;
161 }
162 void control_check(double inf, double sup) {
163 typedef std::numeric_limits< double > dbl;
164 if(inf > sup) {
165 std::cerr.precision(dbl::max_digits10);
166 std::cerr << "inf() > sup() !!" << std::endl;
167 std::cerr << "inf()=" << inf << std::endl;
168 std::cerr << "sup()=" << sup << std::endl;
170 }
171 if(control_ < inf || control_ > sup) {
172 std::cerr.precision(dbl::max_digits10);
173 std::cerr << "[" << inf << "," << sup << "]"
174 << " " << control_.estimate() << ":"
175 << control_.rep().length()
176 << std::endl;
178 }
179 }
180 expansion_nt control_;
181#else
182 void control_set(double x) {
183 geo_argused(x);
184 }
185 void control_set(const expansion_nt& x) {
186 geo_argused(x);
187 }
188 void control_set(const intervalBase& x) {
189 geo_argused(x);
190 }
191 void control_negate() {
192 }
193 void control_add(const intervalBase& x) {
194 geo_argused(x);
195 }
196 void control_sub(const intervalBase& x) {
197 geo_argused(x);
198 }
199 void control_mul(const intervalBase& x) {
200 geo_argused(x);
201 }
202 void control_check(double inf, double sup) {
203 geo_argused(inf);
204 geo_argused(sup);
205 }
206#endif
207 };
208
209
210/*******************************************************************/
211
215 class intervalRU : public intervalBase {
216 public:
217
230 struct Rounding {
231 Rounding() {
232 set_FPU_round_to_upper();
233 }
234 ~Rounding() {
235 set_FPU_round_to_nearest();
236 }
237 };
238
239 intervalRU() :
240 intervalBase(),
241 ln_(0.0),
242 u_(0.0)
243 {
244 control_check();
245 }
246
247 intervalRU(double x) :
248 intervalBase(x),
249 ln_(-x),
250 u_(x)
251 {
252 control_check();
253 }
254
255 intervalRU(double l, double u) : ln_(-l), u_(u) {
256 // note: we cannot control check here.
257 }
258
259 intervalRU(const intervalRU& rhs) = default;
260
261 intervalRU(const expansion_nt& rhs) {
262 *this = rhs;
263 }
264
265 intervalRU& operator=(const intervalRU& rhs) = default;
266
267 intervalRU& operator=(double rhs) {
268 ln_ = -rhs;
269 u_ = rhs;
270 control_set(rhs);
271 control_check();
272 return *this;
273 }
274
275 intervalRU& operator=(const expansion_nt& rhs) {
276
277 // Optimized expansion-to-interval conversion:
278 //
279 // Add components starting from the one of largest magnitude
280 // Stop as soon as next component is smaller than ulp (and then
281 // expand interval by ulp).
282
283 index_t l = rhs.length();
284 ln_ = -rhs.component(l-1);
285 u_ = rhs.component(l-1);
286
287 for(int comp_idx=int(l)-2; comp_idx>=0; --comp_idx) {
288 double comp = rhs.component(index_t(comp_idx));
289 u_ += comp;
290 ln_ -= comp;
291 if(comp > 0) {
292 double new_u = u_ + comp;
293 if(new_u == u_) {
294 u_ = std::nextafter(
295 u_, std::numeric_limits<double>::infinity()
296 );
297 break;
298 } else {
299 u_ = new_u;
300 }
301 } else {
302 // If we stored l, we would write:
303 // new_l = l + comp
304 // But we store ln = -l, so we write:
305 // -new_ln = -ln + comp
306 // Which means:
307 // new_ln = ln - comp
308
309 double new_ln = ln_ - comp;
310 if(new_ln == ln_) {
311 ln_ = std::nextafter(
312 ln_, std::numeric_limits<double>::infinity()
313 );
314 break;
315 } else {
316 ln_ = new_ln;
317 }
318 }
319 }
320
321 control_set(rhs);
322 control_check();
323 return *this;
324 }
325
326 double inf() const {
327 return -ln_;
328 }
329
330 double sup() const {
331 return u_;
332 }
333
334 double estimate() const {
335 // 0.5*(lb+ub) ->
336 return 0.5*(-ln_+u_);
337 }
338
339 bool is_nan() const {
340 return !(ln_==ln_) || !(u_==u_);
341 }
342
343 Sign2 sign() const {
344 // Branchless
345 int lz = int(ln_ == 0);
346 int ln = int(ln_ > 0); // inverted, it is ln_ !!!
347 int lp = int(ln_ < 0); // inverted, it is ln_ !!!
348 int uz = int(u_ == 0);
349 int un = int(u_ < 0);
350 int up = int(u_ > 0);
351 Sign2 result = Sign2(
352 ln*up*SIGN2_NP+
353 lp*up*SIGN2_PP+
354 lz*up*SIGN2_ZP+
355 ln*un*SIGN2_NN+
356 ln*uz*SIGN2_NZ
357 );
358 result = Sign2(
359 int(result) +
360 int(result==SIGN2_ZERO && !(lz&&uz)) * SIGN2_ERROR
361 );
362 return result;
363 }
364
365 intervalRU& negate() {
366 std::swap(ln_, u_);
367 control_negate();
368 control_check();
369 return *this;
370 }
371
372 intervalRU& operator+=(const intervalRU &x) {
373 // lb += x.lb -> -lbn += -x.lbn -> lbn += x.lbn
374 ln_ += x.ln_;
375 u_ += x.u_;
376 control_add(x);
377 control_check();
378 return *this;
379 }
380
381 intervalRU& operator-=(const intervalRU &x) {
382 // +=(x.negate()) ->
383 ln_ += x.u_;
384 u_ += x.ln_;
385 control_sub(x);
386 control_check();
387 return *this;
388 }
389
390
391 intervalRU& operator*=(const intervalRU &b) {
392 // get bounds of both operands
393 double aln = ln_;
394 double au = u_;
395 double bln = b.ln_;
396 double bu = b.u_;
397
398 // negated bounds round to upper
399 // (equivalent to bounds round to lower)
400 double lln = (-aln)*bln;
401 double lun = aln*bu;
402 double uln = au*bln;
403 double uun = (-au)*bu;
404
405 // bounds round to upper
406 double ll = aln*bln;
407 double lu = (-aln)*bu;
408 double ul = au*(-bln);
409 double uu = au*bu;
410
411 ln_ = std::max(std::max(lln,lun),std::max(uln,uun));
412 u_ = std::max(std::max(ll,lu),std::max(ul,uu));
413
414 control_mul(b);
415 control_check();
416 return *this;
417 }
418
419 protected:
420
421#ifdef INTERVAL_CHECK
422 void control_check() {
423 // expansion_nt used in control_check() operates
424 // in round to nearest mode !!
425 set_FPU_round_to_nearest();
426 intervalBase::control_check(inf(),sup());
427 set_FPU_round_to_upper();
428 }
429#else
430 void control_check() {
431 }
432#endif
433 double ln_;
434 double u_;
435 };
436
437
438 inline intervalRU operator+(const intervalRU& a, const intervalRU& b) {
439 intervalRU result = a;
440 return result += b;
441 }
442
443 inline intervalRU operator-(const intervalRU& a, const intervalRU& b) {
444 intervalRU result = a;
445 return result -= b;
446 }
447
448 inline intervalRU operator*(const intervalRU& a, const intervalRU& b) {
449 intervalRU result = a;
450 return result *= b;
451 }
452
453 /*************************************************************************/
454
462 class intervalRN : public intervalBase {
463 public:
464
465 // operates in default rounding mode
466 // (so Rounding subclass does nothing)
467 struct Rounding {
468 Rounding() {
469 }
470 ~Rounding() {
471 }
472 };
473
474 intervalRN() :
475 intervalBase(),
476 lb_(0.0),
477 ub_(0.0)
478 {
479 control_check();
480 }
481
482 intervalRN(double x) :
483 intervalBase(x),
484 lb_(x),
485 ub_(x)
486 {
487 control_check();
488 }
489
490 intervalRN(double l, double u) : lb_(l), ub_(u) {
491 // note: we cannot control check here.
492 }
493
494
495 intervalRN(const intervalRN& rhs) = default;
496
497 intervalRN(const expansion_nt& rhs) {
498 *this = rhs;
499 }
500
501 intervalRN& operator=(const intervalRN& rhs) = default;
502
503 intervalRN& operator=(double rhs) {
504 lb_ = rhs;
505 ub_ = rhs;
506 control_set(rhs);
507 control_check();
508 return *this;
509 }
510
511 intervalRN& operator=(const expansion_nt& rhs) {
512
513 // Optimized expansion-to-interval conversion:
514 //
515 // Add components starting from the one of largest magnitude
516 // Stop as soon as next component is smaller than ulp (and then
517 // expand interval by ulp).
518
519 index_t l = rhs.length();
520 lb_ = rhs.component(l-1);
521 ub_ = rhs.component(l-1);
522
523 for(int comp_idx=int(l)-2; comp_idx>=0; --comp_idx) {
524 double comp = rhs.component(index_t(comp_idx));
525 if(comp > 0) {
526 double nub = ub_ + comp;
527 if(nub == ub_) {
528 ub_ = std::nextafter(
529 ub_, std::numeric_limits<double>::infinity()
530 );
531 break;
532 } else {
533 ub_ = nub;
534 adjust();
535 }
536 } else {
537 double nlb = lb_ + comp;
538 if(nlb == lb_) {
539 lb_ = std::nextafter(
540 lb_, -std::numeric_limits<double>::infinity()
541 );
542 break;
543 } else {
544 lb_ = nlb;
545 adjust();
546 }
547 }
548 }
549 control_set(rhs);
550 control_check();
551 return *this;
552 }
553
554 double inf() const {
555 return lb_;
556 }
557
558 double sup() const {
559 return ub_;
560 }
561
562 double estimate() const {
563 return 0.5*(lb_ + ub_);
564 }
565
566 bool is_nan() const {
567 return !(lb_==lb_) || !(ub_==ub_);
568 }
569
570 Sign2 sign() const {
571 if(is_nan()) {
572 return SIGN2_ERROR;
573 }
574 // Branchless (not sure it is super though...)
575 int lz = int(lb_ == 0);
576 int ln = int(lb_ < 0);
577 int lp = int(lb_ > 0);
578 int uz = int(ub_ == 0);
579 int un = int(ub_ < 0);
580 int up = int(ub_ > 0);
581 Sign2 result = Sign2(
582 ln*up*SIGN2_NP+
583 lp*up*SIGN2_PP+
584 lz*up*SIGN2_ZP+
585 ln*un*SIGN2_NN+
586 ln*uz*SIGN2_NZ
587 );
588 result = Sign2(
589 int(result) +
590 int(result==SIGN2_ZERO && !(lz&&uz)) * SIGN2_ERROR
591 );
592 return result;
593 }
594
595 intervalRN& negate() {
596 lb_ = -lb_;
597 ub_ = -ub_;
598 std::swap(lb_, ub_);
599 control_negate();
600 control_check();
601 return *this;
602 }
603
604 intervalRN& operator+=(const intervalRN &x) {
605 lb_ += x.lb_;
606 ub_ += x.ub_;
607 adjust();
608 control_add(x);
609 control_check();
610 return *this;
611 }
612
613 intervalRN& operator-=(const intervalRN &x) {
614 lb_ -= x.ub_;
615 ub_ -= x.lb_;
616 adjust();
617 control_sub(x);
618 control_check();
619 return *this;
620 }
621
622 intervalRN& operator*=(const intervalRN &x) {
623 if(!is_nan() && !x.is_nan()) {
624 double ll = lb_*x.lb_;
625 double lu = lb_*x.ub_;
626 double ul = ub_*x.lb_;
627 double uu = ub_*x.ub_;
628
629 if(!(ll==ll)) ll = 0.0;
630 if(!(lu==lu)) lu = 0.0;
631 if(!(ul==ul)) ul = 0.0;
632 if(!(uu==uu)) uu = 0.0;
633
634 if(lu<ll) std::swap(lu, ll);
635 if(ul<ll) std::swap(ul, ll);
636 if(uu<ll) std::swap(uu, ll);
637
638 if(lu>uu) uu = lu;
639 if(ul>uu) uu = ul;
640
641 lb_ = ll;
642 ub_ = uu;
643
644 adjust();
645 } else {
646 lb_ = std::numeric_limits<double>::quiet_NaN();
647 ub_ = std::numeric_limits<double>::quiet_NaN();
648 }
649 control_mul(x);
650 control_check();
651 return *this;
652 }
653
654 protected:
655
656 void adjust() {
657 static constexpr double i = std::numeric_limits<double>::infinity();
658 static constexpr double e = std::numeric_limits<double>::epsilon();
659 // e = nextafter(1.0) - 1.0
660 static constexpr double m = std::numeric_limits<double>::min();
661 // m = smallest normalized
662 static constexpr double l = 1.0-e;
663 static constexpr double u = 1.0+e;
664 static constexpr double em = e*m;
665
666 if(lb_==lb_ && ub_==ub_ && (lb_!=ub_ || (lb_!=i && lb_!=-i))) {
667
668 if(lb_>ub_) {
669 std::swap(lb_, ub_);
670 }
671
672 if(lb_>m) {
673 lb_ *= l;
674 } else if(lb_<-m) {
675 lb_ *= u;
676 } else {
677 lb_ -= em;
678 }
679
680 if(ub_>m) {
681 ub_ *= u;
682 } else if(ub_<-m) {
683 ub_ *= l;
684 } else {
685 ub_ += em;
686 }
687 } else {
688 lb_ = std::numeric_limits<double>::quiet_NaN();
689 ub_ = std::numeric_limits<double>::quiet_NaN();
690 }
691 }
692
693#ifdef INTERVAL_CHECK
694 void control_check() {
695 intervalBase::control_check(inf(),sup());
696 }
697#else
698 void control_check() {
699 }
700#endif
701
702 private:
703 double lb_;
704 double ub_;
705 };
706
707 inline intervalRN operator+(const intervalRN& a, const intervalRN& b) {
708 intervalRN result = a;
709 return result += b;
710 }
711
712 inline intervalRN operator-(const intervalRN& a, const intervalRN& b) {
713 intervalRN result = a;
714 return result -= b;
715 }
716
717 inline intervalRN operator*(const intervalRN& a, const intervalRN& b) {
718 intervalRN result = a;
719 return result *= b;
720 }
721
722 /**********************************************************************/
723
730 public:
731 struct Rounding {
732 Rounding() {
733 geo_argused(this); // silence a warning in predicate filters.
734 }
735 };
736
737 intervalDummy() {
738 }
739
740 intervalDummy(double x) {
741 geo_argused(x);
742 }
743
744 intervalDummy(double l, double u) {
745 geo_argused(l);
746 geo_argused(u);
747 }
748
749 intervalDummy(const intervalDummy& rhs) = default;
750
751 intervalDummy(const expansion_nt& rhs) {
752 geo_argused(rhs);
753 }
754
755 intervalDummy& operator=(const intervalDummy& rhs) = default;
756
757 intervalDummy& operator=(double rhs) {
758 geo_argused(rhs);
759 return *this;
760 }
761
762 intervalDummy& operator=(const expansion_nt& rhs) {
763 geo_argused(rhs);
764 return *this;
765 }
766
767 double inf() const {
768 return -std::numeric_limits<double>::infinity();
769 }
770
771 double sup() const {
772 return std::numeric_limits<double>::infinity();
773 }
774
775 double estimate() const {
776 return std::numeric_limits<double>::quiet_NaN();
777 }
778
779 bool is_nan() const {
780 return true;
781 }
782
783 Sign2 sign() const {
784 return SIGN2_NP;
785 }
786
787 intervalDummy& negate() {
788 return *this;
789 }
790
791 intervalDummy& operator+=(const intervalDummy &x) {
792 geo_argused(x);
793 return *this;
794 }
795
796 intervalDummy& operator-=(const intervalDummy &x) {
797 geo_argused(x);
798 return *this;
799 }
800
801 intervalDummy& operator*=(const intervalDummy &x) {
802 geo_argused(x);
803 return *this;
804 }
805 };
806
807 inline intervalDummy operator+(
808 const intervalDummy& a, const intervalDummy& b
809 ) {
810 intervalDummy result = a;
811 return result += b;
812 }
813
814 inline intervalDummy operator-(
815 const intervalDummy& a, const intervalDummy& b
816 ) {
817 intervalDummy result = a;
818 return result -= b;
819 }
820
821 inline intervalDummy operator*(
822 const intervalDummy& a, const intervalDummy& b
823 ) {
824 intervalDummy result = a;
825 return result *= b;
826 }
827
828 /**********************************************************************/
829
830#ifdef GEO_NO_INTERVALS
831 typedef intervalDummy interval_nt;
832#else
833 typedef intervalRN interval_nt; // Seems that valgrind does not support RU
834 //typedef intervalRU interval_nt;
835#endif
836
837
839 template <> struct is_scalar<interval_nt> {
840 typedef interval_nt type;
841 static constexpr bool value = true;
842 };
843
851 template <> inline vec2Hg<interval_nt> operator-(
852 const vec2Hg<interval_nt>& p1, const vec2Hg<interval_nt>& p2
853 ) {
854 return vec2Hg<interval_nt>(
855 det2x2(p1.x,p1.w,p2.x,p2.w),
856 det2x2(p1.y,p1.w,p2.y,p2.w),
857 p1.w*p2.w
858 );
859 }
860
861
869 template <> inline vec3Hg<interval_nt> operator-(
870 const vec3Hg<interval_nt>& p1, const vec3Hg<interval_nt>& p2
871 ) {
872 return vec3Hg<interval_nt>(
873 det2x2(p1.x,p1.w,p2.x,p2.w),
874 det2x2(p1.y,p1.w,p2.y,p2.w),
875 det2x2(p1.z,p1.w,p2.z,p2.w),
876 p1.w * p2.w
877 );
878 }
879}
880
881#endif
#define geo_assert_not_reached
Sets a non reachable point in the program.
Definition assert.h:177
#define geo_assert(x)
Verifies that a condition is met.
Definition assert.h:149
Expansion_nt (expansion Number Type) is used to compute the sign of polynoms exactly.
Base class for interval arithmetics.
Definition interval_nt.h:74
Dummy interval class, that does not compute anything and that always says that sign is undetermined.
Number type for interval arithmetics.
Interval arithmetics in round to upper (RU) mode.
2d vector with homogeneous coordinates
Definition vechg.h:60
3d vector with homogeneous coordinates
Definition vechg.h:185
High-level interface to multi-precision arithmetics.
Global Vorpaline namespace.
Quaternion operator-(const Quaternion &a, const Quaternion &b)
Computes the difference between two Quaternion.
Definition quaternion.h:252
void geo_argused(const T &)
Suppresses compiler warnings about unused parameters.
Definition argused.h:60
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:330
Sign
Integer constants that represent the sign of a value.
Definition numeric.h:69
@ ZERO
Definition numeric.h:73
@ NEGATIVE
Definition numeric.h:71
@ POSITIVE
Definition numeric.h:75
T det2x2(const T &a11, const T &a12, const T &a21, const T &a22)
Computes a two-by-two determinant.
Definition determinant.h:58
Quaternion operator+(const Quaternion &a, const Quaternion &b)
Computes the sum of two Quaternion.
Definition quaternion.h:239
vecng< DIM, FT > operator*(const Matrix< DIM, FT > &M, const vecng< DIM, FT > &x)
Computes a matrix vector product.
Definition matrix.h:536
Sets FPU rounding mode for using this type of interval.
type traits for scalars
Definition numeric.h:390
Generic implementation of geometric vectors in homogeneous coordinates.