1 /*
2 File timetable_defs.cpp
3 */
4
5 /***************************************************************************
6 timetable_defs.cpp - description
7 -------------------
8 begin : Sat Mar 15 2003
9 copyright : (C) 2003 by Lalescu Liviu
10 email : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
11 ***************************************************************************/
12
13 /***************************************************************************
14 * *
15 * This program is free software: you can redistribute it and/or modify *
16 * it under the terms of the GNU Affero General Public License as *
17 * published by the Free Software Foundation, either version 3 of the *
18 * License, or (at your option) any later version. *
19 * *
20 ***************************************************************************/
21
22 #include "timetable_defs.h"
23
24 //#include <ctime>
25 #include <chrono>
26
27 #include <QHash>
28
29 #include <QLocale>
30
31 bool checkForUpdates;
32
33 QString internetVersion;
34
35 int STUDENTS_COMBO_BOXES_STYLE=STUDENTS_COMBO_BOXES_STYLE_SIMPLE;
36
37 /**
38 FET version
39 */
40 const QString FET_VERSION="6.2.0";
41
42 /**
43 FET language
44 */
45 QString FET_LANGUAGE="en_US";
46
47 /**
48 The output directory. Please be careful when editing it,
49 because the functions add a FILE_SEP sign at the end of it
50 and then the name of a file. If you make OUTPUT_DIR="",
51 there will be problems.
52 */
53 QString OUTPUT_DIR;
54
55 bool LANGUAGE_STYLE_RIGHT_TO_LEFT;
56
57 QString LANGUAGE_FOR_HTML;
58
59 /**
60 Timetable html css javaScript Level, by Volker Dirr
61 */
62 int TIMETABLE_HTML_LEVEL;
63
64 bool TIMETABLE_HTML_PRINT_ACTIVITY_TAGS;
65
66 bool PRINT_DETAILED_HTML_TIMETABLES;
67
68 bool PRINT_DETAILED_HTML_TEACHERS_FREE_PERIODS;
69
70 bool PRINT_NOT_AVAILABLE_TIME_SLOTS;
71
72 bool PRINT_BREAK_TIME_SLOTS;
73
74 bool PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME;
75
76 bool DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS;
77
78 bool TIMETABLE_HTML_REPEAT_NAMES;
79
80 bool VERBOSE;
81
82 //these hashes are needed to get the IDs for html and css in timetableexport and statistics
83 /*QHash<QString, QString> hashSubjectIDs;
84 QHash<QString, QString> hashActivityTagIDs;
85 QHash<QString, QString> hashStudentIDs;
86 QHash<QString, QString> hashTeacherIDs;
87 QHash<QString, QString> hashRoomIDs;
88 QHash<QString, QString> hashDayIDs;*/
89
90 /**
91 A log file explaining how the xml input file was parsed
92 */
93 const QString XML_PARSING_LOG_FILENAME="file_open.log";
94
95 /**
96 The predefined names of the days of the week
97 */
98 /*
99 const QString PREDEFINED_DAYS_OF_THE_WEEK[]={"Monday", "Tuesday", "Wednesday",
100 "Thursday", "Friday", "Saturday", "Sunday", "Monday2",
101 "Tuesday2", "Wednesday2", "Thursday2", "Friday2", "Saturday2", "Sunday2",
102 "Monday3", "Tuesday3", "Wednesday3",
103 "Thursday3", "Friday3", "Saturday3", "Sunday3", "Monday4",
104 "Tuesday4", "Wednesday4", "Thursday4", "Friday4", "Saturday4", "Sunday4"};
105 */
106
107 /**
108 File and directory separator
109 */
110 const QString FILE_SEP="/";
111
protect(const QString & str)112 QString protect(const QString& str) //used for XML
113 {
114 QString p=str;
115 p.replace("&", "&");
116 p.replace("\"", """);
117 p.replace(">", ">");
118 p.replace("<", "<");
119 p.replace("'", "'");
120 return p;
121 }
122
protect2(const QString & str)123 QString protect2(const QString& str) //used for HTML
124 {
125 QString p=str;
126 p.replace("&", "&");
127 p.replace("\"", """);
128 p.replace(">", ">");
129 p.replace("<", "<");
130 //p.replace("'", "'");
131 return p;
132 }
133
protect2vert(const QString & str)134 QString protect2vert(const QString& str) //used for HTML
135 {
136 QString p=str;
137 p.replace("&", "&");
138 p.replace("\"", """);
139 p.replace(">", ">");
140 p.replace("<", "<");
141 //p.replace("'", "'");
142
143 QString returnstring;
144 for(int i=0; i<p.size();i++){
145 QString a=p.at(i);
146 QString b="<br />";
147 returnstring.append(a);
148 returnstring.append(b);
149 }
150 return returnstring;
151 }
152
153 ///////begin tricks
weight_sscanf(const QString & str,const char * fmt,double * result)154 void weight_sscanf(const QString& str, const char* fmt, double* result)
155 {
156 assert(QString(fmt)==QString("%lf"));
157
158 bool ok;
159 double myres=customFETStrToDouble(str, &ok);
160 if(!ok)
161 (*result)=-2.5; //any value that does not belong to {>=0.0 and <=100.0} or {-1.0}
162 //not -1.0 because of modify multiple constraints min days between activities,
163 //-1 there represents any weight
164 //potential bug found by Volker Dirr
165 else
166 (*result)=myres;
167 }
168
number(int n)169 QString CustomFETString::number(int n)
170 {
171 return QString::number(n);
172 }
173
number(double x)174 QString CustomFETString::number(double x)
175 {
176 QString tmp=QString::number(x, 'f', CUSTOM_DOUBLE_PRECISION);
177
178 //remove trailing zeroes AFTER the decimal points
179 if(tmp.contains('.')){
180 int n=tmp.length()-1;
181 int del=0;
182 while(tmp.at(n)=='0'){
183 n--;
184 del++;
185 }
186 if(tmp.at(n)=='.'){
187 n--;
188 del++;
189 }
190 tmp.chop(del);
191 }
192
193 return tmp;
194 }
195
numberPlusTwoDigitsPrecision(double x)196 QString CustomFETString::numberPlusTwoDigitsPrecision(double x)
197 {
198 QString tmp=QString::number(x, 'f', CUSTOM_DOUBLE_PRECISION+2);
199
200 //remove trailing zeroes AFTER the decimal points
201 if(tmp.contains('.')){
202 int n=tmp.length()-1;
203 int del=0;
204 while(tmp.at(n)=='0'){
205 n--;
206 del++;
207 }
208 if(tmp.at(n)=='.'){
209 n--;
210 del++;
211 }
212 tmp.chop(del);
213 }
214
215 return tmp;
216 }
217
customFETStrToDouble(const QString & str,bool * ok)218 double customFETStrToDouble(const QString& str, bool* ok)
219 {
220 QLocale c(QLocale::C);
221
222 //tricks to convert numbers like 97.123456789 to 97.123457, to CUSTOM_DOUBLE_PRECISION (6) decimal digits after the decimal point
223 double tmpd=c.toDouble(str, ok);
224 if(ok!=0)
225 if((*ok)==false)
226 return tmpd;
227 QString tmps=CustomFETString::number(tmpd);
228 return c.toDouble(tmps, ok);
229 }
230 ///////end tricks
231
232 bool BEEP_AT_END_OF_GENERATION=true;
233 bool ENABLE_COMMAND_AT_END_OF_GENERATION=true;
234 QString commandAtEndOfGeneration=QString("");
235 //bool DETACHED_NOTIFICATION=false;
236 //int terminateCommandAfterSeconds=0;
237 //int killCommandAfterSeconds=0;
238
239 /*
240 int XX;
241 int YY;
242 int ZZ;
243
244 //random routines
245 void initRandomKnuth()
246 {
247 assert(MM==2147483647);
248 assert(AA==48271);
249 assert(QQ==44488);
250 assert(RR==3399);
251
252 assert(MMM==2147483399);
253 assert(MMM==MM-248);
254 assert(AAA==40692);
255 assert(QQQ==52774);
256 assert(RRR==3791);
257
258 //a few tests
259 XX=123; YY=123;
260 int tttt=randomKnuth1MM1();
261 assert(XX==5937333);
262 assert(YY==5005116);
263 assert(tttt==932217);
264
265 XX=4321; YY=54321;
266 tttt=randomKnuth1MM1();
267 assert(XX==208578991);
268 assert(YY==62946733);
269 assert(tttt==145632258);
270
271 XX=87654321; YY=987654321;
272 tttt=randomKnuth1MM1();
273 assert(XX==618944401);
274 assert(YY==1625301246);
275 assert(tttt==1141126801);
276
277 XX=1; YY=1;
278 tttt=randomKnuth1MM1();
279 assert(XX==48271);
280 assert(YY==40692);
281 assert(tttt==7579);
282
283 XX=MM-1; YY=MMM-1;
284 tttt=randomKnuth1MM1();
285 assert(XX==2147435376);
286 assert(YY==2147442707);
287 assert(tttt==2147476315);
288
289 XX=100; YY=1000;
290 tttt=randomKnuth1MM1();
291 assert(XX==4827100);
292 assert(YY==40692000);
293 assert(tttt==2111618746);
294 //////////
295
296 //unsigned tt=unsigned(time(nullptr));
297 qint64 tt=qint64(time(nullptr));
298
299 //XX is the current time
300 //XX = 1 + ( (unsigned(tt)) % (unsigned(MM-1)) );
301 XX = 1 + int( tt%(qint64(MM-1)) );
302 assert(XX>0);
303 assert(XX<MM);
304
305 //YY is the next random, after initializing YY with the current time
306 //YY = 1 + ( (unsigned(tt)) % (unsigned(MMM-1)) );
307 YY = 1 + int( tt%(qint64(MMM-1)) );
308 assert(YY>0);
309 assert(YY<MMM);
310 YY=AAA*(YY%QQQ)-RRR*(YY/QQQ);
311 if(YY<0)
312 YY+=MMM;
313 assert(YY>0);
314 assert(YY<MMM);
315
316 ZZ=XX-YY;
317 if(ZZ<=0)
318 ZZ+=MM-1; //-1 is not written in Knuth TAOCP vol. 2 third edition; I think it would be an improvement. (Later edit: yes, the author confirmed that).
319 assert(ZZ>0);
320 assert(ZZ<MM); //again, modified from Knuth TAOCP vol. 2 third edition, ZZ is strictly lower than MM (the author confirmed that, too).
321 }
322
323 int randomKnuth1MM1()
324 {
325 assert(XX>0);
326 assert(XX<MM);
327
328 XX=AA*(XX%QQ)-RR*(XX/QQ);
329 if(XX<0)
330 XX+=MM;
331
332 assert(XX>0);
333 assert(XX<MM);
334
335 assert(YY>0);
336 assert(YY<MMM);
337
338 YY=AAA*(YY%QQQ)-RRR*(YY/QQQ);
339 if(YY<0)
340 YY+=MMM;
341
342 assert(YY>0);
343 assert(YY<MMM);
344
345 ZZ=XX-YY;
346 if(ZZ<=0)
347 ZZ+=MM-1; //-1 is not written in Knuth TAOCP vol. 2 third edition; I think it would be an improvement. (Later edit: yes, the author confirmed that).
348 assert(ZZ>0);
349 assert(ZZ<MM); //again, modified from Knuth TAOCP vol. 2 third edition, ZZ is strictly lower than MM (the author confirmed that, too).
350
351 return ZZ;
352 }
353
354 int randomKnuth(int k)
355 {
356 //like in Knuth TAOCP vol.2, reject some numbers (very few), so that the distribution is perfectly uniform
357 for(;;){
358 int U=randomKnuth1MM1();
359 if( U <= k * ((MM-1)/k) )
360 return U%k;
361 }
362 }
363 */
364
365 //MRG32k3a rng;
366
367 const qint64 MRG32k3a::m1 = Q_INT64_C(4294967087);
368 const qint64 MRG32k3a::m2 = Q_INT64_C(4294944443);
369 const qint64 MRG32k3a::a12 = Q_INT64_C(1403580);
370 const qint64 MRG32k3a::a13n = Q_INT64_C(810728);
371 const qint64 MRG32k3a::a21 = Q_INT64_C(527612);
372 const qint64 MRG32k3a::a23n = Q_INT64_C(1370589);
373
MRG32k3a()374 MRG32k3a::MRG32k3a()
375 {
376 //not permitted values, so we check that we don't forget to init this RNG in another place.
377 s10=s11=s12=0;
378 s20=s21=s22=0;
379 }
380
~MRG32k3a()381 MRG32k3a::~MRG32k3a()
382 {
383 }
384
initializeMRG32k3a(qint64 _s10,qint64 _s11,qint64 _s12,qint64 _s20,qint64 _s21,qint64 _s22)385 void MRG32k3a::initializeMRG32k3a(qint64 _s10, qint64 _s11, qint64 _s12,
386 qint64 _s20, qint64 _s21, qint64 _s22)
387 {
388 assert(m1==Q_INT64_C(4294967296)-Q_INT64_C(209));
389 assert(m1==Q_INT64_C(4294967087));
390
391 assert(m2==Q_INT64_C(4294967296)-Q_INT64_C(22853));
392 assert(m2==Q_INT64_C(4294944443));
393
394 assert(a12==Q_INT64_C(1403580));
395 assert(a13n==Q_INT64_C(810728));
396
397 assert(a21==Q_INT64_C(527612));
398 assert(a23n==Q_INT64_C(1370589));
399
400 assert(_s10>=0);
401 assert(_s11>=0);
402 assert(_s12>=0);
403
404 assert(_s20>=0);
405 assert(_s21>=0);
406 assert(_s22>=0);
407
408 assert(_s10 < m1);
409 assert(_s11 < m1);
410 assert(_s12 < m1);
411
412 assert(_s20 < m2);
413 assert(_s21 < m2);
414 assert(_s22 < m2);
415
416 assert(_s10>0 || _s11>0 || _s12>0);
417 assert(_s20>0 || _s21>0 || _s22>0);
418
419 s10=_s10;
420 s11=_s11;
421 s12=_s12;
422
423 s20=_s20;
424 s21=_s21;
425 s22=_s22;
426 }
427
initializeMRG32k3a()428 void MRG32k3a::initializeMRG32k3a()
429 {
430 qint64 _s10, _s11, _s12, _s20, _s21, _s22;
431
432 //qint64 tt=qint64(time(nullptr));
433
434 std::chrono::seconds s=std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
435 qint64 si=static_cast<qint64>(s.count());
436 //cout<<"si=="<<si<<endl;
437 assert(si>=0);
438 _s10=si%m1;
439 if(_s10==0) //just in case :-) . It could even be allowed to be 0, but then we wouldn't have a certain guarantee that not all seeds in component 1 are 0.
440 _s10=1;
441
442 _s20=si%m2;
443 if(_s20==0) //just in case :-) . It could even be allowed to be 0, but then we wouldn't have a certain guarantee that not all seeds in component 2 are 0.
444 _s20=1;
445
446 /*_s10 = 1 + tt%(m1-1);
447 assert(_s10>=1);
448 assert(_s10<m1);
449
450 _s20 = 1 + tt%(m2-1);
451 assert(_s20>=1);
452 assert(_s20<m2);*/
453
454 //Using ideas and code from https://stackoverflow.com/questions/19555121/how-to-get-current-timestamp-in-milliseconds-since-1970-just-the-way-java-gets
455 //and https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back
456 //and https://stackoverflow.com/questions/18022927/convert-high-resolution-clock-time-into-an-integer-chrono/18023064
457 std::chrono::nanoseconds ns=std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch());
458 qint64 nsi=static_cast<qint64>(ns.count());
459 //cout<<"nsi=="<<nsi<<endl;
460 assert(nsi>=0);
461
462 _s11=nsi%1000000000;
463
464 std::chrono::nanoseconds ns2=std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch());
465 qint64 nsi2=static_cast<qint64>(ns2.count());
466 //cout<<"nsi2=="<<nsi2<<endl;
467 assert(nsi2>=0);
468
469 _s21=nsi2%1000000000;
470
471 _s12=0; //We could try other better methods, but they need to be portable.
472 _s22=0;
473
474 initializeMRG32k3a(_s10, _s11, _s12, _s20, _s21, _s22);
475 }
476
uiMRG32k3a()477 unsigned int MRG32k3a::uiMRG32k3a()
478 {
479 assert(s10>0 || s11>0 || s12>0);
480 assert(s20>0 || s21>0 || s22>0);
481
482 qint64 p, p1, p2;
483
484 /* Component 1 */
485 p1 = a12*s11 - a13n*s10;
486 p1%=m1;
487 if(p1<0)
488 p1+=m1;
489 assert(p1>=0 && p1<m1);
490 s10 = s11;
491 s11 = s12;
492 s12 = p1;
493
494 /* Component 2 */
495 p2 = a21*s22 - a23n*s20;
496 p2%=m2;
497 if(p2<0)
498 p2+=m2;
499 assert(p2>=0 && p2<m2);
500 s20 = s21;
501 s21 = s22;
502 s22 = p2;
503
504 /* Combination */
505 p=p1-p2;
506 if(p<0)
507 p+=m1;
508 assert(p>=0 && p<m1);
509
510 return (unsigned int)(p);
511 }
512
513 /*double MRG32k3a::dMRG32k3a()
514 {
515 double p=double(uiMRG32k3a())/double(m1);
516
517 assert(p>=0.0);
518 assert(p<1.0);
519
520 return p;
521 }*/
522
intMRG32k3a(int k)523 int MRG32k3a::intMRG32k3a(int k)
524 {
525 qint64 q=(qint64(uiMRG32k3a())*qint64(k))/m1;
526 assert(q<qint64(k));
527 int r=int(q);
528
529 return r;
530 }
531