From dd740b6c89099a757eedf27385d99ea5b011a5ca Mon Sep 17 00:00:00 2001
From: Tue Herlau <tuhe@dtu.dk>
Date: Sat, 17 Apr 2021 23:14:13 +0200
Subject: [PATCH] vesion 1.7: L2-Norm fixed plus minor improvement of progress
 display

---
 .../__pycache__/unitgrade.cpython-38.pyc      | Bin 13899 -> 13974 bytes
 .../unitgrade_helpers.cpython-38.pyc          | Bin 6936 -> 8229 bytes
 unitgrade/__pycache__/version.cpython-38.pyc  | Bin 166 -> 166 bytes
 unitgrade/unitgrade.py                        |   5 ++
 unitgrade/unitgrade_helpers.py                |  52 +++++++++++++++++-
 unitgrade/version.py                          |   2 +-
 6 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/unitgrade/__pycache__/unitgrade.cpython-38.pyc b/unitgrade/__pycache__/unitgrade.cpython-38.pyc
index 79d28c2c207464f86831a1a24c58a1908f9fbb16..49ec789f81c61461975b3223eaa6b5b60596fd78 100644
GIT binary patch
delta 2069
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

delta 1811
zcmbQ1dpd_Vl$V!_fq{YH;q$5lnT@=wc^Eq;-{qH`e2qs_lsTKFsHKEGg{g*lHbV+?
z4eM-%xh#_-1mq`M@|G}iO<u>VHTeZ^9IpV#07ec*Hbyx{k;$Qa#*A5$@A7NwlrSz}
zsbN{jSOYRBt%Nm&v6+#Pp@cPssfJ|%+d_uf40D-4A~g(I?33T{c{6fMw%}Khv14Fh
zSjk!>!N9;!<Od@BL4-Ak2$)>UFC&=4z`#(<2e(v;aq=2|1IB5S@A3y4)v$nUTgaHg
zl+98!sf0C!8RU3~JteFuELdzV5-`{1C<2?$2C~EhM0kP-kR3%nAeJwP06DBEcyghk
zu$V0a14Aju83?~iF)B^w6zpWIpFCNxlCfzruh0_4w#l1>lGq@gm@J?s!djAAT++GO
zSoj|!2gqDa#v;GTmZD0G{gY!vw{S!=FfeE`7Wq$>5L05DJUK>GcX5UoBTRpucqAK0
zQ&HsPv*NalQIokP!ezi_$ADZH%fP^Ji#<8Ns3<kL<Q8LUQR3t}2|31|$#W$x2t|QZ
zB!G-(f&^^F<a$X-#=VngN@iMwf+Ukcgc67d1Q8)10_4l0Fc2#oL_~rJut}L9R@P)I
zDQi}4E>144%~etlm>3f#KNOUhTr4Zfcyw~7>=ec;ljY>*^Tva0WiL_#X~~^@N=}Cj
zY*pdpKXMYBc_2qK78ezOLX{O{!L7-r^6mn;Ak~E+0wh+%1(Fs8#rqLZpo5}`gOP)u
zgRLlMa-f0i<csnf8J|pUR(QzxVsfft0b|wVYl?ELO$-bS&nN#>^yIDvnFQiOO)6(#
zV0er$iHVVmsi=JNLuT2{lavw}WotmLVoEP50%Z*d!3{E@j)8&U+hhTiNs^r)t~iJQ
zD?yUot&+f4Gg(Gek`<)-=VU8YHOBhMiK-ToU2x@KjbJ^X0RJ?3lWG~$ABM?VY9@?*
zljGIo1hPR&L2^YCK`gNMWm_2-7+!-M4N8_Aj4Uw7#KBe6x_PhKWG0n1ki*&2Q%lk^
zb5e^ML3%|&LM-JenMFk+Ab!#05>0cqNg!tb<c*qg&Y)BQPUM<Akfbpcq=UU6u`(w=
zF{Q`}q;f7uh^esn7Gw4;#=xRp5SO*MB(bRE7Gq&i+2le)aYpvdT3V|avlqeDa~Bk)
zCg<lCl$NBXXmS?K2TAmS2(UZg))v`=#K1lVCB$1CP@9W2*&*&(36cjns%SaLUdH%a
zESV*#xnOIBSr;%cFsM$B(1~T7KY5#uHXDc!iDlL)pdw=Oe;si)5G$E+@&X=-$tJp8
z^57)NQe*})jwLNKFQup-WJeJwrLq;}Prj?G#ahh3z+gU^M^B!yc(aZk2cuyINS5gq
zYg$fzV#zJ$%)Am!rXp}kVN8Ui5!9sMH91wkmlvF2L4MU_DaxPxU*A~1gn@y<m63s=
z7+iEPu`u#6axwBT@-T8R@-Y^bOb#^ouCfi}98fARVh6dAF|TMD$aWS;fE)zLE}NWV
zD8m>uxzn(T@z7)*BNfJFlMRg|SV0QoC;J&Kk~{=bb`nH@Ja&scBe6KKq@<|m)MQR$
z2ga1mUdASj9-#bGBnwg`2O=Cn#3_)StVM}=>8V9vL(YOk!D)cCI43o=py)72;0(w~
z(BfnjD1)+|U|?V<n0(K~l;r>e1H&XPaRHEPiq3&lgXAFbqQ0MjfgunS0vrqs3>=JH
zyd10?JVhW;P32qc@$o77$?@?;ag!@d<#nfl^n%=Xizzd|hy}!}01=>+UbF+mItC)H
zgNV74kC^(XfJzBS(g)@8B2ca=0>yt3C`OAwp<lFrvWb}*quJzWGacS)0eJxqAyGba
I4n7VZ0M=Efn*aa+

diff --git a/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc b/unitgrade/__pycache__/unitgrade_helpers.cpython-38.pyc
index bed82f87d21feaedd5ccb707a1ea1b71a1d99ad4..712bb3bb40300a849453141c82e5f9afc3bac086 100644
GIT binary patch
delta 2729
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

delta 1542
zcmZ4LFvE;5l$V!_fq{YH#gnRp|7sigZm{z6GB7akFfcGUGcYg|+b~Z4%DSz-hB1X9
zo1^GSi9iZRGb1BIiC_&Uh_2zR<th;<5v<{AW(4s|1X94_B|-~?ON17PEM!>7n8GE=
zkR@8nUBa5hwm__gdm&>ALkf2*lO#h5k2pgu4_I8hhG!w;1jZtZ5`h$6s7ZV^Jk3mu
z3?%|7-25P+8jfHFO@YnfobwqcbMVNpFfuSOOjhPu$S5)SD9?<^>3sfjytmkjQVa5n
zN{VC{7#ND=K!h@gP+(wSh?;zb&t!5VzdfVH<b(Xmj2x2<1teG;K&H$W7oD6WaEUQy
zvZ<hMpc(@M!%HRx1_n*$TWn>CIi;z^x0vz@Zm}m8Cl(bYR%$X8X)!P`++xfq5(60y
zCZs?jtfd8s$=Ok$kYfV{E0Yi-7h{pv<PCyyj6IXj3m#!+j{Pusnov69vdRC192pmE
zb`Ta~)JRbfXDCstQEp}wXGl>LX8`%Ogd;_%Mpy*Qt`V=1jaN@mp4=fKFMp#%yhb)l
zqDCb}w3n$?Ay2J@qedk~r9>r#u|_yWb@DM0Yk9R^))=N*^;(S@xf+cc^%}JjwHnzh
z&1S|L*(|OU^~nmNii)#p6c)%WWME_{k<U_Cpa^E6nv^7}F1{{BBabOXvsSf6HASIB
ztws~##>uNh9T}x2zY*28)|$gsBU&S7!%(ALBOWhOqfsLsFPx%XBbFj0&M=!{E>o>e
zie!y=mdI>|6rCE0*$i`8YIRFEYIIUmCI^XW3+p0O!c<M3Am+=cH~F5Jc%;4*L#=*|
zUX6Z=z6gT^L#;uIL5g7uL#<&6M~YF6fH(sv>}m{a^izzRnZy}VOvD*#3~LNhOu;-e
zNLbbgEznIdPvI|7t6|6z0sBB_vY)s#zr`G;TB91H8lg0%U<OUg$ra)=7&9gdN-Sek
zo4iB9R45db2pEgNNl2A}fuTxnGNYu-WNFDJ7FSTZStaRP?+8i)P9Or5V{Wl!WTvE~
z=H22*&d)6<ElEu&3IU}(mH@}#;3_UHEiDB%M^7JD7frSzG@Y!OC8@c^MUfz*Kzge9
zK&k^vQ;SP7^Yau6e=+J;aUr->9I75xs=kxUq`aI#ZYu&M+gpsqMFC((-(oH<Dbi#r
zase3^2O_}96ik5ADu+!@Vs27OqTMY928PcJlcc>EZ%y`=&QLc7rDTrclA^Sd%-mG4
z^KY@2r4|)u=I0gZgCto%5|cOZimP*F78jQ$CFdj-7vJKHj|Vg2<BM28_QAuXD0(uF
zj2SpEZ?UA7CFa~>$;`_vDKeNGBBLzs4l<FoD8Do><rZ^pVnvZJNOSz;J{fg+FA!54
zM6iNXu_YE1q~@g*f%2B7ago*Ji!y3zxA=-P^2_5hQgaI8({d8iiy}bkWkG}rhyayu
zMVXUjWfj!H!C(uD4yHVxTkIwA#U+VFCAV0Mlk<yGZ!zY9vvrZ<<P=$D*;_22=(xp{
zS$>NZqKqjyxd@aXZZW1#UMedu4~nQ;?8&7?MX7luMIhfsv6d94CKumgDlaZ_p8Qx=
zL(T@|0&tjv2~fZn88I+0B!P;EW0N)Iav8NIPnT1kyhqNG(P;8FIVDk0cocz3pCV?E
z<}46VHd$9*Ny-Go)ByzqM`BTWL1IyHYEczPEPryQytT3hNQNgdB_%$wD7`cn<fwR%
fEU1Jl0*9p0WLs{j$q(hNIaN3~7#JBC8U6tP1$2$H

diff --git a/unitgrade/__pycache__/version.cpython-38.pyc b/unitgrade/__pycache__/version.cpython-38.pyc
index 8dc5bac8678643c646bd1057bdfb5299c1e65b24..74567f3b5e3d3f07730bb308aaec25f3d90a3ad9 100644
GIT binary patch
delta 24
fcmZ3+xQvlIl$V!_fq{Wxw^Q{*ZevFCiT3FLKpF*!

delta 24
fcmZ3+xQvlIl$V!_fq{Wx>&vQ%+{TP%6YbLhMo|VR

diff --git a/unitgrade/unitgrade.py b/unitgrade/unitgrade.py
index d4f69fc..f829f0a 100644
--- a/unitgrade/unitgrade.py
+++ b/unitgrade/unitgrade.py
@@ -100,6 +100,8 @@ class QItem(unittest.TestCase):
         diff = np.abs( (np.asarray(computed).flat- np.asarray(expected)).flat )
         nrm = np.sqrt(np.sum( diff ** 2))
 
+        self.error_computed = nrm
+
         if nrm > tol:
             print(f"Not equal within tolerance {tol}; norm of difference was {nrm}")
             print(f"Element-wise differences {diff.tolist()}")
@@ -109,6 +111,8 @@ class QItem(unittest.TestCase):
         if tol == None:
             tol = self.tol
         diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )
+        self.error_computed = np.max(diff)
+
         if np.max(diff) > tol:
             print("Not equal within tolerance {tol}")
             print(f"Element-wise differences {diff.tolist()}")
@@ -119,6 +123,7 @@ class QItem(unittest.TestCase):
             tol = self.tol
         diff = np.abs( (np.asarray(computed) - np.asarray(expected)) )
         diff = diff / (1e-8 + np.abs( (np.asarray(computed) + np.asarray(expected)) ) )
+        self.error_computed = np.max(np.abs(diff))
         if np.sum(diff > tol) > 0:
             print(f"Not equal within tolerance {tol}")
             print(f"Element-wise differences {diff.tolist()}")
diff --git a/unitgrade/unitgrade_helpers.py b/unitgrade/unitgrade_helpers.py
index 45adf1b..f14c2b7 100644
--- a/unitgrade/unitgrade_helpers.py
+++ b/unitgrade/unitgrade_helpers.py
@@ -71,6 +71,53 @@ def evaluate_report_student(report, question=None, qitem=None, unmute=None, pass
     results, table_data = evaluate_report(report, question=question, show_progress_bar=not unmute, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute,
                                           show_tol_err=show_tol_err)
 
+    try:  # For registering stats.
+        import unitgrade_private
+        import irlc.lectures
+        import xlwings
+        from openpyxl import Workbook
+        import pandas as pd
+        from collections import defaultdict
+        dd = defaultdict(lambda: [])
+        error_computed = []
+        for k1, (q, _) in enumerate(report.questions):
+            for k2, (item, _) in enumerate(q.items):
+                dd['question_index'].append(k1)
+                dd['item_index'].append(k2)
+                dd['question'].append(q.name)
+                dd['item'].append(item.name)
+                dd['tol'].append(0 if not hasattr(item, 'tol') else item.tol)
+                error_computed.append(0 if not hasattr(item, 'error_computed') else item.error_computed)
+
+        qstats = report.wdir + "/" + report.name + ".xlsx"
+
+        if os.path.isfile(qstats):
+            d_read = pd.read_excel(qstats).to_dict()
+        else:
+            d_read = dict()
+
+        for k in range(1000):
+            key = 'run_'+str(k)
+            if key in d_read:
+                dd[key] = list(d_read['run_0'].values())
+            else:
+                dd[key] = error_computed
+                break
+
+        workbook = Workbook()
+        worksheet = workbook.active
+        for col, key in enumerate(dd.keys()):
+            worksheet.cell(row=1, column=col+1).value = key
+            for row, item in enumerate(dd[key]):
+                worksheet.cell(row=row+2, column=col+1).value = item
+
+        workbook.save(qstats)
+        workbook.close()
+
+    except ModuleNotFoundError as e:
+        s = 234
+        pass
+
     if question is None:
         print("Provisional evaluation")
         tabulate(table_data)
@@ -161,7 +208,7 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
                 q.has_called_init_ = True
                 q_time =np.round(  time.time()-start, 2)
 
-                print(" "* max(0,nL - len(q_title_print) ) + " (" + str(q_time) + " seconds)") # if q.name in report.payloads else "")
+                print(" "* max(0,nL - len(q_title_print) ) + (" (" + str(q_time) + " seconds)" if q_time >= 0.1 else "") ) # if q.name in report.payloads else "")
                 print("=" * nL)
 
             item.question = q # Set the parent question instance for later reference.
@@ -186,7 +233,8 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa
 
             if not hidden:
                 ss = "PASS" if current == possible else "*** FAILED"
-                ss += " ("+ str(tsecs) + " seconds)"
+                if tsecs >= 0.1:
+                    ss += " ("+ str(tsecs) + " seconds)"
                 print(ss)
 
         ws, possible, obtained = upack(q_)
diff --git a/unitgrade/version.py b/unitgrade/version.py
index 32efefd..283b03a 100644
--- a/unitgrade/version.py
+++ b/unitgrade/version.py
@@ -1 +1 @@
-__version__ = "0.1.6"
\ No newline at end of file
+__version__ = "0.1.7"
\ No newline at end of file
-- 
GitLab