1 // Copyright (c) 2013-2015 John Abbott
2 // This file is part of the CoCoALib suite of examples.
3 // You are free to use any part of this example in your own programs.
4
5 #include "CoCoA/library.H"
6
7 using namespace std;
8
9 //----------------------------------------------------------------------
10 const string ShortDescription =
11 "**ADVANCED** This example program is for advanced CoCoALib users. \n"
12 "It shows how to use SmallFpImpl for efficient arithmetic in a small\n"
13 "prime finite field. Not for the faint-hearted! \n";
14
15 const string LongDescription =
16 "**ADVANCED** This example program is for advanced CoCoALib users. \n"
17 "SmallFpImpl enables you to perform arithmetic efficiently in a small \n"
18 "prime finite field. The catch is that efficient use is not as simple \n"
19 "as using RingElems directly. We take as a specific illustrative \n"
20 "example the computation of an inner product. Be prepared to spend \n"
21 "some time reading and comprehending the code! \n";
22 //----------------------------------------------------------------------
23
24 namespace CoCoA
25 {
26
27 // The impl of inner product for RingElem is pretty simple and clear:
InnerProd_RINGELEM(const vector<RingElem> & u,const vector<RingElem> & v)28 RingElem InnerProd_RINGELEM(const vector<RingElem>& u, const vector<RingElem>& v)
29 {
30 ring Fp = owner(u[0]);
31 const long n = len(u);
32 RingElem ans(Fp);
33 for (long i=0; i < n; ++i)
34 ans += u[i]*v[i];
35 return ans;
36 }
37
38
39 // Now some faster functions using SmallFpImpl -- faster but less clear.
40 // Handy typedef to make reading/writing the code simpler!!!
41 typedef SmallFpImpl::value FpElem;
42
43
44 // Here is a SIMPLE BUT INEFFICIENT impl using SmallFpImpl
45 // (because every intermediate value is normalized).
InnerProd_SLOW(const SmallFpImpl & Fp,const vector<FpElem> & u,const vector<FpElem> & v)46 FpElem InnerProd_SLOW(const SmallFpImpl& Fp, const vector<FpElem>& u, const vector<FpElem>& v)
47 {
48 const long n = len(u);
49 FpElem ans; // initally zero
50 for (long i=0; i < n; ++i)
51 ans = Fp.myAdd(ans, Fp.myMul(u[i],v[i]));
52 return ans;
53 }
54
55
56 // We present 2 fast impls (which avoid many intermediate reductions):
57 // (A) is slightly clearer, while
58 // (B) is slightly faster.
59 // You decide whether the extra complication of impl (B) is worth the speed gain!
60
61 // Impl (A) for "fast" inner product;
62 // it is much fiddlier than the RingElem implementation above!
InnerProd_A(const SmallFpImpl & Fp,const vector<FpElem> & u,const vector<FpElem> & v)63 FpElem InnerProd_A(const SmallFpImpl& Fp, const vector<FpElem>& u, const vector<FpElem>& v)
64 {
65 const long n = len(u);
66 CoCoA_ASSERT(len(v) == n);
67 const long MaxSafeIters = Fp.myMaxIters();
68
69 SmallFpImpl::NonRedValue ans; // initially zero
70 long NextHalfNormalize = MaxSafeIters;
71 for (long i=0; i < n; ++i)
72 {
73 ans += u[i]*v[i]; // <--- the actual computation, the rest is overhead!
74 if (i < NextHalfNormalize) continue;
75 NextHalfNormalize += MaxSafeIters; // overflow?
76 ans = Fp.myHalfNormalize(ans);
77 }
78 return Fp.myNormalize(ans);
79 }
80
81 // Impl (B) for "fast" inner product;
82 // it is harder to understand than (A), but is a bit faster (on my computer).
InnerProd_B(const SmallFpImpl & Fp,const vector<FpElem> & u,const vector<FpElem> & v)83 FpElem InnerProd_B(const SmallFpImpl& Fp, const vector<FpElem>& u, const vector<FpElem>& v)
84 {
85 const long n = len(u);
86 const long MaxSafeIters = Fp.myMaxIters();
87
88 long i = 0; // loop counter
89 long NextNormalize = 0;
90 SmallFpImpl::NonRedValue ans;
91 while (NextNormalize < n)
92 {
93 NextNormalize += MaxSafeIters;
94 if (NextNormalize > n) NextNormalize = n;
95 for (; i < NextNormalize; ++i)
96 ans += u[i]*v[i]; // <--- the actual computation, the rest is overhead!
97 ans = Fp.myHalfNormalize(ans);
98 }
99 return Fp.myNormalize(ans);
100 }
101
102
103 ///////////////////////////////////////////////////////
TimeTrialRingElem(long p)104 void TimeTrialRingElem(long p)
105 {
106 ring Fp = NewZZmod(p);
107 vector<RingElem> u; u.reserve(p*p);
108 vector<RingElem> v; v.reserve(p*p);
109 for (long i=0; i < p; ++i)
110 for (long j=0; j < p; ++j)
111 {
112 u.push_back(RingElem(Fp,i));
113 v.push_back(RingElem(Fp,j));
114 }
115
116 // Timing the computation of the inner product:
117 const double StartTime = CpuTime();
118 const RingElem InProd = InnerProd_RINGELEM(u, v);
119 const double EndTime = CpuTime();
120 cout << "Ans is " << InProd << endl;
121 cout << "Using ring ZZmod(" << p << ") time is " << EndTime-StartTime << endl;
122 }
123
124
TimeTrialSmallFp(long p)125 void TimeTrialSmallFp(long p)
126 {
127 if (!SmallFpImpl::IsGoodCtorArg(p)) return;//????
128 SmallFpImpl Fp(p);
129 // Create two vectors to work on
130 vector<FpElem> u; u.reserve(p*p);
131 vector<FpElem> v; v.reserve(p*p);
132 for (long i=0; i < p; ++i)
133 for (long j=0; j < p; ++j)
134 {
135 u.push_back(Fp.myReduce(i));
136 v.push_back(Fp.myReduce(j));
137 }
138
139 // Timing method SLOW (normalize every intermediate result)
140 const double StartTime_SLOW = CpuTime();
141 const FpElem InProd_SLOW = InnerProd_SLOW(Fp, u, v);
142 const double EndTime_SLOW = CpuTime();
143 cout << "Ans is " << Fp.myExport(InProd_SLOW) << endl;
144 cout << "Using impl (SLOW) for p=" << p << " time is " << (EndTime_SLOW - StartTime_SLOW) << endl;
145
146 // Timing method (A)
147 const double StartTime_A = CpuTime();
148 const FpElem InProd_A = InnerProd_A(Fp, u, v);
149 const double EndTime_A = CpuTime();
150 cout << "Ans is " << Fp.myExport(InProd_A) << endl;
151 cout << "Using impl (A) for p=" << p << " time is " << (EndTime_A - StartTime_A) << endl;
152
153 // Timing method (B)
154 const double StartTime_B = CpuTime();
155 const FpElem InProd_B = InnerProd_B(Fp, u, v);
156 const double EndTime_B = CpuTime();
157 cout << "Ans is " << Fp.myExport(InProd_B) << endl;
158 cout << "Using impl (B) for p=" << p << " time is " << (EndTime_B - StartTime_B) << endl;
159
160 }
161
162
program()163 void program()
164 {
165 GlobalManager CoCoAFoundations;
166 cout << ShortDescription << endl;
167
168 const int p = NextPrime(2048);
169 TimeTrialRingElem(p);
170 TimeTrialSmallFp(p);
171 }
172
173 } // end of namespace CoCoA
174
175
176 //----------------------------------------------------------------------
177 // Use main() to handle any uncaught exceptions and warn the user about them.
main()178 int main()
179 {
180 try
181 {
182 CoCoA::program();
183 return 0;
184 }
185 catch (const CoCoA::ErrorInfo& err)
186 {
187 cerr << "***ERROR*** UNCAUGHT CoCoA error";
188 ANNOUNCE(cerr, err);
189 }
190 catch (const std::exception& exc)
191 {
192 cerr << "***ERROR*** UNCAUGHT std::exception: " << exc.what() << endl;
193 }
194 catch(...)
195 {
196 cerr << "***ERROR*** UNCAUGHT UNKNOWN EXCEPTION" << endl;
197 }
198
199 CoCoA::BuildInfo::PrintAll(cerr);
200 return 1;
201 }
202
203 //----------------------------------------------------------------------
204 // RCS header/log in the next few lines
205 // $Header: /Volumes/Home_1/cocoa/cvs-repository/CoCoALib-0.99/examples/ex-SmallFp3.C,v 1.2 2016/11/10 17:35:39 abbott Exp $
206 // $Log: ex-SmallFp3.C,v $
207 // Revision 1.2 2016/11/10 17:35:39 abbott
208 // Summary: Made this quicker -- too slow and needed too much RAM for my netbook
209 //
210 // Revision 1.1 2015/11/04 10:12:13 abbott
211 // Summary: Renamed from ex-SmallFp1
212 //
213 // Revision 1.5 2015/06/29 15:49:01 bigatti
214 // *** empty log message ***
215 //
216 // Revision 1.4 2015/06/29 13:17:29 bigatti
217 // -- code inside namespace CoCoA
218 //
219 // Revision 1.3 2014/04/03 15:43:07 abbott
220 // Summary: Reduced size of prime p (o/w too slow with debugging on some machines)
221 // Author: JAA
222 //
223 // Revision 1.2 2013/05/27 14:48:18 abbott
224 // Added typedef for FpElem to make code more readable.
225 //
226 // Revision 1.1 2013/05/27 12:55:04 abbott
227 // Added new example ex-SmallFp1.C
228 //
229 // Revision 1.6 2012/11/30 14:04:55 abbott
230 // Increased visibility of comment saying "put your code here".
231 //
232 // Revision 1.5 2010/12/17 16:07:54 abbott
233 // Ensured that all i/o in examples is on standard C++ streams
234 // (rather than GlobalInput(), etc).
235 //
236 // Revision 1.4 2008/10/07 12:12:54 abbott
237 // Removed useless commented out #include.
238 //
239 // Revision 1.3 2007/05/31 16:06:16 bigatti
240 // -- removed previous unwanted checked-in version
241 //
242 // Revision 1.1.1.1 2007/03/09 15:16:11 abbott
243 // Imported files
244 //
245 // Revision 1.9 2007/03/07 11:51:40 bigatti
246 // -- improved test alignment
247 //
248 // Revision 1.8 2007/03/03 14:15:45 bigatti
249 // -- "foundations" renamed into "GlobalManager"
250 //
251 // Revision 1.7 2007/03/02 17:46:40 bigatti
252 // -- unique RingZ and RingQ
253 // -- requires foundations.H ; foundations blah; (thik of a better name)
254 //
255 // Revision 1.6 2007/03/02 10:47:53 cocoa
256 // First stage of RingZ modifications -- tests do not compile currently, Anna will fix this.
257 //
258 // Revision 1.5 2007/03/01 13:52:59 bigatti
259 // -- minor: fixed typo
260 //
261 // Revision 1.4 2007/02/28 15:15:56 bigatti
262 // -- minor: removed quotes in description
263 //
264 // Revision 1.3 2007/02/12 16:27:43 bigatti
265 // -- added strings ShortDescription and LongDescription for indexing
266 //
267 // Revision 1.2 2007/02/10 18:44:03 cocoa
268 // Added "const" twice to each test and example.
269 // Eliminated dependency on io.H in several files.
270 // Improved BuildInfo, and added an example about how to use it.
271 // Some other minor cleaning.
272 //
273 // Revision 1.1.1.1 2006/05/30 11:39:36 cocoa
274 // Imported files
275 //
276 // Revision 1.1 2006/03/12 21:28:34 cocoa
277 // Major check in after many changes
278 //
279