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