Skip to content

Instantly share code, notes, and snippets.

@gongzhitaao
Last active June 4, 2019 18:56
Show Gist options
  • Save gongzhitaao/508b4cfd99cb93353ee34bacdbd24529 to your computer and use it in GitHub Desktop.
Save gongzhitaao/508b4cfd99cb93353ee34bacdbd24529 to your computer and use it in GitHub Desktop.
COMP 2710 2019 Spring Grading Script

This gist contains all the grading script for COMP2710 2019 Spring session.

from enum import IntFlag, auto
from subprocess import run, Popen, PIPE, TimeoutExpired
from types import SimpleNamespace
from zipfile import ZipFile
import os
import re
import numpy as np
args = SimpleNamespace(
**{
'n_test': 50,
'tmpdir': 'tmp',
# http://stackoverflow.com/a/385597/1429714
're_float': r'[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?',
})
def prepare_tests(args):
frac = 0.001
w_man = np.random.uniform(1.0, 100.0, args.n_test)
w_rat = np.random.uniform(1.0, 100.0, args.n_test)
die_rat = np.random.uniform(1.0, 20.0, args.n_test)
die_man = die_rat * w_man / (w_rat * frac)
X_test = np.vstack([w_man, w_rat, die_rat]).T
y_test = np.reshape(die_man, [-1, 1])
return X_test, y_test
def get_name(fname):
"""Split fname.
Filename example: shawaaron_3467955_144194936_hw1_ags0047-1.cpp
"""
try:
base, ext = fname.split(os.extsep, 1)
except ValueError:
base = fname
ext = 'damnit'
parts = base.split('_')
# e.g., shawaaron, ags0047
name, auid = parts[0].lower(), parts[-1].split('-')[0].lower()
return name, auid, ext.lower()
devnull = open(os.devnull, 'w')
X_test, y_test = prepare_tests(args)
os.makedirs(args.tmpdir, exist_ok=True)
summaries = []
class Status(IntFlag):
ac = 0
fe = auto() # file error
ce = auto() # compile error
wa = auto() # wrong answer
late = auto() # late submission
tle = auto() # time limit exceed
rte = auto() # runtime error
with ZipFile('hw1-s2.zip', 'r') as zf:
files = zf.namelist()
n = len(files)
for i, itm in enumerate(files):
name, auid, ext = get_name(itm)
summary = {'name': name, 'auid': auid, 'comment': '', 'score': 0}
comment = []
score = 0
stat = Status.ac
print('[{0:03d}/{1}] {2}'.format(i + 1, n, auid), end=' ', flush=True)
if ext not in ['cpp', 'cc', 'c', 'c++']:
stat = Status.fe
else:
# extract the submission, which should be a cpp file
zf.extract(itm, args.tmpdir)
cpp = os.path.join(args.tmpdir, itm)
# compile, and ignore any error messages
ret = run(['g++', '-o', 'hw1', cpp], stderr=devnull)
if 0 != ret.returncode:
stat = Status.ce
else:
if 'late' in itm:
stat |= Status.late
# Wow! it compiles!!
score += 80
pts = 0
for x, y in zip(X_test, y_test):
w_man, w_rat, die_rat = x
curstat = Status.ac
# feed input and grab output from the program
pipe = Popen('./hw1', stdin=PIPE, stdout=PIPE)
inputs = ' '.join(
np.char.mod('%f', [w_rat, die_rat, w_man]))
try:
out = pipe.communicate(
input=inputs.encode('utf8'), timeout=2)
except TimeoutExpired:
curstat |= Status.tle
pipe.kill()
except Exception:
curstat |= Status.rte
pipe.kill()
try:
out = out[0].decode('utf8')
matches = re.findall(args.re_float, out)
ybar = float(matches[-1])
if not np.isclose(ybar, y, rtol=0.01):
curstat |= Status.wa
if not (curstat | Status.ac):
pts += 1
except Exception:
curstat |= Status.rte
stat |= curstat
if Status.tle in stat:
break
score += int(pts / args.n_test * 20)
summary['score'] = score
if Status.fe in stat:
comment.append('not cpp file')
else:
if Status.ce in stat:
comment.append('ce')
if Status.wa in stat:
comment.append('wa')
if Status.late in stat:
comment.append('late')
if Status.tle in stat:
comment.append('tle')
if Status.rte in stat:
comment.append('rte')
summary['comment'] = ' '.join(comment)
summaries.append(summary)
print('{0:.2f} {1}'.format(summary['score'], summary['comment']))
with open('hw1.csv', 'w') as w:
for itm in summaries:
w.write('{0},{1},{2},{3}\n'.format(itm['name'], itm['auid'],
itm['score'], itm['comment']))
import os
import re
from zipfile import ZipFile
from subprocess import run, Popen, PIPE, TimeoutExpired
import math
from enum import IntEnum
import numpy as np
# solution for hw2
def amortize(loan, rate_per_year, pay_per_month):
balance = [loan]
interest = [math.nan]
principal = [math.nan]
rate_per_month = rate_per_year * 0.01 / 12
if loan*rate_per_month < pay_per_month:
while balance[-1] > 0:
i = balance[-1] * rate_per_month
p = pay_per_month - i
b = balance[-1] - p
if b < 0:
p = balance[-1]
b = 0.
balance += [b]
interest += [i]
principal += [p]
return balance[1:], interest[1:], principal[1:]
# http://stackoverflow.com/a/385597/1429714
re_float = r'[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?'
re_line_bad = (r'\n\s*\d+' +
r'\s+\$\s*(?P<balance>' + re_float +
r')\s+\$\s*' + re_float +
r'\s+\$?\s*' + re_float +
r'\s+\$\s*(?P<interest>' + re_float +
r')\s+\$\s*(?P<principal>' + re_float + ')')
re_line_good = (r'\n\s*\d+' +
r'\s+\$\s*(?P<balance>' + re_float +
r')\s+\$\s*' + re_float +
r'\s+' + re_float +
r'\s+\$\s*(?P<interest>' + re_float +
r')\s+\$\s*(?P<principal>' + re_float + ')')
# re_line_bad = (r'\n\s*\d+' +
# r'\s+(?P<balance>' + re_float +
# r')\s+' + re_float +
# r'\s+' + re_float +
# r'\s+(?P<interest>' + re_float +
# r')\s+(?P<principal>' + re_float + ')')
N = 10
class Stat(IntEnum):
GOOD = 0 # full credit
LATE = 1 # late submission
COMPILE_ERR = 2 # compile error
DOLLAR_SIGN = 4 # dollar sign before interest
EDGE_CASE = 8 # edge cases
OTHER = 16 # other
CREDIT = 100
Penalty = [0] * 17
Penalty[Stat.GOOD] = 0
Penalty[Stat.LATE] = 10
Penalty[Stat.COMPILE_ERR] = 80
Penalty[Stat.DOLLAR_SIGN] = 5
Penalty[Stat.OTHER] = max(int(CREDIT*0.5/N), 1)
def gen_test(N):
"""Generate test cases for HW2.
We make sure there are no edge cases, i.e., the loan will always be paid
off in the end.
"""
# The amount need to pey per month (loan/M) is usually much higher than
# the interest. So we roughly need 8 month to pay off all the loan. We
# may have some months off since we did not take into consideration the
# interest yet. This number controls roughly how many entries we have per
# test cases.
M = 8
loan = np.random.uniform(low=10, high=999, size=N)
rate = np.random.uniform(low=0.1, high=2.0, size=N)
pay_min = np.maximum(loan * rate * 0.01 / 12, loan / M)
pay_max = pay_min * 1.5
tmp = np.random.uniform(low=0.5, size=N)
pay = pay_min + (pay_max - pay_min) * tmp
X_test = np.stack([loan, rate, pay], axis=1)
y_test = [
np.stack(amortize(a, b, c), axis=1)
for a, b, c in zip(loan, rate, pay)
]
return X_test, y_test
X_test, y_test = gen_test(10)
devnull = open(os.devnull, 'w')
summary = {}
with ZipFile('sess1.zip', 'r') as zf:
files = zf.namelist()
n = len(files)
for i, f in enumerate(files):
tmp = f.split('_')
name = tmp[0]
print('[{0:03d}/{1}] {2}'.format(i+1, n, name),
end=' ', flush=True)
stat = Stat.GOOD
penalty = 0
# 10% penalty for late submission
if 'late' in tmp:
stat |= Stat.LATE
penalty += Penalty[Stat.LATE]
print(' late ', end=' ', flush=True)
_, ext = os.path.splitext(f)
ext = ext.lower()
if ext not in ['.cpp', '.cc', '.c', '.c++']:
stat |= Stat.COMPILE_ERR
penalty += min(Penalty[Stat.COMPILE_ERR], CREDIT)
print('{0} compile error'.format(CREDIT-penalty))
summary[name] = {'pts': CREDIT-penalty, 'stat': stat}
continue
# extract to ./tmp/
zf.extract(f, path='tmp')
# compile, and ignore any error messages
ret = run(['g++', '-o', 'hw2', 'tmp/'+f], stderr=devnull)
# compilation error
if 0 != ret.returncode:
stat |= Stat.COMPILE_ERR
penalty += Penalty[Stat.COMPILE_ERR]
summary[name] = {'pts': CREDIT-penalty, 'stat': stat}
print('{0} compile error'.format(CREDIT-penalty))
continue
# Wow! it compiles!!
for x in X_test:
# feed input and grab output from the program
pipe = Popen('./hw2', stdin=PIPE, stdout=PIPE)
inputs = ' '.join(np.char.mod('%f', x))
fail = False
try:
out = pipe.communicate(input=inputs.encode('utf8'), timeout=1)
out = out[0].decode('utf8')
except TimeoutExpired:
stat |= Stat.OTHER
pipe.kill()
fail = True
except Exception:
pipe.kill()
fail = True
if fail:
continue
# Extract balance, interest and principal. Note that
# there should be NO dollar sign ($) before interest, but
# some students unintentionally added it. 5% penalty for
# not following the format.
matches = re.findall(re_line_good, out)
if 0 == len(matches):
matches = re.findall(re_line_bad, out)
if not (stat & Stat.DOLLAR_SIGN):
stat |= Stat.DOLLAR_SIGN
penalty += Penalty[Stat.DOLLAR_SIGN]
y0, y1, y2 = amortize(x[0], x[1], x[2])
y_test = np.stack([y0, y1, y2], axis=1)
y_pred = np.array(matches, dtype=np.float32)
if y_test.shape[0] != y_pred.shape[0]:
# That the length does not match means your algorithm
# is totally wrong.
stat |= Stat.OTHER
penalty += Penalty[Stat.OTHER]
else:
# the values in two arrays should be roughly the same.
# Due to rounding errors and conversion to/from
# strings, a large tolerance is used.
diff = np.max(y_test-y_pred)
if diff > 0.1:
stat |= Stat.OTHER
penalty += Penalty[Stat.OTHER]
if penalty >= CREDIT:
penalty = CREDIT
break
summary[name] = {'pts': CREDIT-penalty, 'stat': stat}
print(CREDIT-penalty)
def comment(stat):
ret = []
if Stat.GOOD == stat:
return 'GOOD'
for s in Stat:
if (s & stat):
ret += [s.name]
return ' '.join(ret)
with open('hw2.csv', 'w') as w:
for k, v in summary.items():
w.write('{0},{1},{2}\n'.format(k, v['pts'],
comment(v['stat'])))
from enum import IntFlag, auto
from subprocess import run, Popen, PIPE, TimeoutExpired
from types import SimpleNamespace
from zipfile import ZipFile
import os
import re
import numpy as np
args = SimpleNamespace(**{
'tmpdir': 'tmp',
})
# http://stackoverflow.com/a/385597/1429714
re_float = r'[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?'
args.matchers = [
r'\s*aaron\s+won\s+.*?\s+duels\s+or\s+(?P<aaron>' + re_float + ')',
r'\s*bob\s+won\s+.*?\s+duels\s+or\s+(?P<bob>' + re_float + ')',
r'\s*charlie\s+won\s+.*?\s+duels\s+or\s+(?P<charlie>' + re_float + ')'
]
args.ytrue = np.array([[38, 42], [41, 25], [21, 33]])
def get_name(fname):
"""Split fname.
Filename example: shawaaron_3467955_144194936_hw1_ags0047-1.cpp
"""
try:
base, ext = fname.split(os.extsep, 1)
except ValueError:
base = fname
ext = 'damnit'
parts = base.split('_')
# e.g., shawaaron, ags0047
name, auid = parts[0].lower(), parts[-1].split('-')[0].lower()
return name, auid, ext.lower()
class Status(IntFlag):
ac = 0
fe = auto() # file error
ce = auto() # compile error
wa = auto() # wrong answer
late = auto() # late submission
tle = auto() # time limit exceed
rte = auto() # runtime error
devnull = open(os.devnull, 'w')
os.makedirs(args.tmpdir, exist_ok=True)
summaries = []
with ZipFile('hw3-s1.zip', 'r') as zf:
files = zf.namelist()
n = len(files)
for i, itm in enumerate(files):
name, auid, ext = get_name(itm)
summary = {'name': name, 'auid': auid, 'comment': '', 'score': 0}
comment = []
penalty = 0
stat = Status.ac
print('[{0:03d}/{1}] {2}'.format(i + 1, n, auid), end=' ', flush=True)
if ext not in ['cpp', 'cc', 'c', 'c++']:
stat = Status.fe
penalty = 100
else:
# extract the submission, which should be a cpp file
zf.extract(itm, args.tmpdir)
cpp = os.path.join(args.tmpdir, itm)
# compile, and ignore any error messages
ret = run(['g++', '-o', 'hw3', cpp], stderr=devnull)
if 0 != ret.returncode:
stat = Status.ce
penalty = 40
else:
if 'late' in itm:
stat |= Status.late
penalty += 10
# Wow! it compiles!!
penalty = 0
curstat = Status.ac
# feed input and grab output from the program
pipe = Popen('./hw3', stdin=PIPE, stdout=PIPE)
inputs = '\n' * 20
try:
out = pipe.communicate(
input=inputs.encode('utf8'), timeout=2)
except TimeoutExpired:
curstat |= Status.tle
penalty = 100
pipe.kill()
except Exception:
curstat |= Status.rte
penalty = 100
pipe.kill()
if curstat == Status.ac:
try:
out = out[0].decode('utf8').lower()
ypred = np.empty([3, 2])
for i, matcher in enumerate(args.matchers):
res = re.findall(matcher, out)
tmp = np.array(res).astype(float)
ypred[i] = np.around(tmp).astype(int)
# check whether sum up to 1
res = np.sum(ypred, axis=0)
tmp = np.sum(np.absolute(res - 100) > 2) * 2
penalty += tmp
if tmp > 0:
curstat |= Status.wa
comment.append('not sum up to 1')
# check results within [-2, 2] error
res = np.absolute(ypred - args.ytrue) > 2
tmp = np.sum(res) * 2
penalty += tmp
if tmp > 0:
curstat |= Status.wa
comment.append('wrong probs')
except Exception as e:
comment.insert(0, str(e))
curstat |= Status.rte
penalty = 100
stat |= curstat
summary['score'] = 100 - penalty
if Status.fe in stat:
comment.append('not cpp file')
else:
if Status.ce in stat:
comment.insert(0, '[ce]')
if Status.wa in stat:
comment.insert(0, '[wa]')
if Status.late in stat:
comment.insert(0, '[late]')
if Status.tle in stat:
comment.insert(0, '[tle]')
if Status.rte in stat:
comment.insert(0, '[rte]')
summary['comment'] = ', '.join(comment)
summaries.append(summary)
print('{0:.2f} {1}'.format(summary['score'], summary['comment']))
with open('hw3.csv', 'w') as w:
for itm in summaries:
w.write('{0},{1},{2},{3}\n'.format(itm['name'], itm['auid'],
itm['score'], itm['comment']))
from enum import IntFlag, auto
from subprocess import run, Popen, PIPE, TimeoutExpired
from types import SimpleNamespace
from zipfile import ZipFile
import os
import numpy as np
from lcs import lenlcs
args = SimpleNamespace(**{
'tmpdir': 'tmp',
'n_tests': 10,
'inp_tpl': 'input{}_{}.txt',
'out_tpl': '{}-output{}.txt',
'prefix': 'hw4',
})
args.inp_tpl = os.path.join(args.tmpdir, args.inp_tpl)
args.out_tpl = os.path.join(args.tmpdir, args.out_tpl)
def gen_test_files(args):
def _helper(i, j):
n = np.random.randint(4, 10)
arr = np.random.randint(0, 100, n).tolist()
arr = sorted(arr)
f = args.inp_tpl.format(i, j)
with open(f, 'w') as w:
w.write('\n'.join(str(x) for x in arr))
for i in range(args.n_tests):
_helper(i, 0)
_helper(i, 1)
# gen_test_files(args)
# import sys
# sys.exit()
def get_name(fname):
"""Split fname.
Filename example: shawaaron_3467955_144194936_hw1_ags0047-1.cpp
"""
try:
base, ext = fname.split(os.extsep, 1)
except ValueError:
base = fname
ext = 'damnit'
parts = base.split('_')
# e.g., shawaaron, ags0047
name, auid = parts[0].lower(), parts[-1].split('-')[0].lower()
return name, auid, ext.lower()
class Status(IntFlag):
ac = 0
fe = auto() # file error
ce = auto() # compile error
wa = auto() # wrong answer
late = auto() # late submission
tle = auto() # time limit exceed
rte = auto() # runtime error
devnull = open(os.devnull, 'w')
os.makedirs(args.tmpdir, exist_ok=True)
summaries = []
with ZipFile('{}-s1.zip'.format(args.prefix), 'r') as zf:
files = zf.namelist()
n = len(files)
for i, itm in enumerate(files):
name, auid, ext = get_name(itm)
summary = {
'name': name,
'auid': auid,
'comment': '',
'score': 0,
'stat': Status.ac,
}
comment = []
penalty = 0
print('[{0:03d}/{1}] {2}'.format(i + 1, n, auid), end=' ', flush=True)
if ext not in ['cpp', 'cc', 'c', 'c++']:
summary['stat'] = Status.fe
penalty = 100
else:
# extract the submission, which should be a cpp file
zf.extract(itm, args.tmpdir)
cpp = os.path.join(args.tmpdir, itm)
# compile, and ignore any error messages
ret = run(['g++', '-o', args.prefix, cpp], stderr=devnull)
if 0 != ret.returncode:
summary['stat'] = Status.ce
penalty = 40
else:
# Wow! it compiles!!
if 'late' in itm:
summary['stat'] |= Status.late
penalty += 10
def _readin(f):
with open(f) as r:
txt = r.read().strip()
ans = [int(e) for e in txt.split()]
return ans
step = 1
for ind in range(args.n_tests):
curstat = Status.ac
# feed input and grab output from the program
pipe = Popen('./{}'.format(args.prefix),
stdin=PIPE,
stdout=PIPE)
f0 = args.inp_tpl.format(ind, 0)
f1 = args.inp_tpl.format(ind, 1)
inputs = ''.join(['\n' * 5, f0, '\n' * 5, f1, '\n' * 5])
output = args.out_tpl.format(auid, ind)
try:
out = pipe.communicate(input=inputs.encode('utf8'),
timeout=2)
except TimeoutExpired:
curstat |= Status.tle
penalty = 100
pipe.kill()
break
except Exception as e:
curstat |= Status.rte
comment.append(str(e))
penalty = 100
pipe.kill()
break
else:
try:
os.rename('output.txt', output)
ybar = _readin(output)
ybar = np.array(ybar)
ans = _readin(f0)
ans += _readin(f1)
ans = np.array(sorted(ans))
if lenlcs(ybar, ans) != len(ans):
curstat |= Status.wa
except FileNotFoundError:
curstat |= Status.rte
comment.append('output file name')
penalty = 5
break
except Exception as e:
comment.append(str(e))
curstat |= Status.rte
penalty = 100
break
finally:
summary['stat'] |= curstat
if curstat != Status.ac:
penalty += step
summary['score'] = 100 - penalty
if Status.fe in summary['stat']:
comment.append('not cpp file')
else:
if Status.ce in summary['stat']:
comment.insert(0, '[ce]')
if Status.wa in summary['stat']:
comment.insert(0, '[wa]')
if Status.late in summary['stat']:
comment.insert(0, '[late]')
if Status.tle in summary['stat']:
comment.insert(0, '[tle]')
if Status.rte in summary['stat']:
comment.insert(0, '[rte]')
summary['comment'] = ', '.join(comment)
summaries.append(summary)
print('{0:.2f} {1}'.format(summary['score'], summary['comment']))
with open('{}.csv'.format(args.prefix), 'w') as w:
for itm in summaries:
w.write('{0},{1},{2},{3}\n'.format(itm['name'], itm['auid'],
itm['score'], itm['comment']))
"""
Longest comment subsequence.
From <https://en.wikipedia.org/wiki/Longest_common_subsequence_problem>
"""
def lenlcs(arr0, arr1):
n1 = len(arr1)
cnt, ind = [[0] * (n1 + 1), [0] * (n1 + 1)], 0
for x in arr0:
ind = 1 - ind
for j, y in enumerate(arr1):
if x == y:
cnt[ind][j + 1] = cnt[1 - ind][j] + 1
else:
cnt[ind][j + 1] = max(cnt[ind][j], cnt[1 - ind][j + 1])
return cnt[ind][n1]
from types import SimpleNamespace
import pandas as pd
args = SimpleNamespace(
**{
'thres': 0.99, # min attendance rate to qualify for lottery
'classes': 12, # number of classes so far
'n': 2 # number of lucky students to draw
})
def roll_dice(fname, args):
sess1 = pd.read_csv('sess1.csv')
sess1.fillna(0, inplace=True)
sess1['Missed'] = sess1['Missed'].astype(int)
sess1['Blocked'] = sess1['Blocked'].astype(bool)
sess1['missed_norm'] = sess1['Missed'] / args.classes
cands = sess1.loc[~sess1['Blocked'] &
(sess1['missed_norm'] < 1 - args.thres)]
winner = cands.sample(args.n)
return winner
w1 = roll_dice('sess1.csv', args)
w2 = roll_dice('sess2.csv', args)
print(w1)
print(w2)
import os
from types import SimpleNamespace
import tarfile
import random
import re
from zipfile import ZipFile
from subprocess import run, Popen, PIPE, TimeoutExpired
import math
import numpy as np
args = SimpleNamespace(
**{
'files': sorted([
'cpuinfo.txt', 'interrupts.txt', 'lspci.txt', 'meminfo.txt',
'simple.cpp'
'commands.script'
]),
'n_test': 50,
'tmpdir': 'tmp',
# http://stackoverflow.com/a/385597/1429714
're_float': r'[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?',
})
def prepare_tests():
# First input is N, denoting the number of intergers. Followed by N
# integers.
X_test = []
for i in range(args.n_test):
N = random.randint(1, 10)
dat = [random.randint(2, 100) for _ in range(N)]
X_test.append([N] + dat)
# Each standard output is a factorial and a standard deviation
y_test = []
for x in X_test:
fact = math.factorial(x[0])
stddev = np.std(x[1:])
y_test.append([fact, stddev])
return X_test, y_test
def iscpp(fname):
_, ext = os.path.splitext(fname)
ext = ext.lower()
return ext in ['.cpp', '.cc', '.c', '.c++']
devnull = open(os.devnull, 'w')
X_test, y_test = prepare_tests()
os.makedirs(args.tmpdir, exist_ok=True)
damnit = []
summaries = []
with ZipFile('proj1-s2.zip', 'r') as zf:
files = zf.namelist()
n = len(files)
for i, submission in enumerate(files):
summary = {'name': '', 'score': 90, 'comment': []}
if not submission.endswith('tar.gz'):
print('---------', submission)
summary['comment'].append('not tar.gz')
damnit.append(summary)
continue
tmp = submission.split('_')
name = tmp[0]
summary['name'] = name
print('[{0:03d}/{1}] {2}'.format(i + 1, n, name), end=' ', flush=True)
# extract the submission, which should be an archive
zf.extract(submission, args.tmpdir)
# make temporary directory for the submission
workdir = os.path.join(args.tmpdir, '{}.d'.format(submission))
os.makedirs(workdir, exist_ok=True)
# extract the submission
tmp = os.path.join(args.tmpdir, submission)
try:
tar = tarfile.open(tmp, "r:gz")
except tarfile.ReadError:
damnit.append(summary)
summary['comment'].append('not tar.gz')
print('tar error')
continue
cppfile = None
for mb in tar.getmembers():
if mb.isreg():
mb.name = os.path.basename(mb.name)
if iscpp(mb.name):
cppfile = os.path.join(workdir, mb.name)
tar.extract(mb, workdir)
# we do not grade late submission
if 'late' in submission:
print('late')
summary['score'] = 60
summary['comment'].append('late')
continue
# no cpp file result in 70
if cppfile is None:
print('No C++ file found')
summary['score'] = 70
summary['comment'].append('no cpp')
damnit.append(summary)
continue
# compile, and ignore any error messages
ret = run(['g++', '-o', 'hw1', cppfile], stderr=devnull)
# compilation error gets 20 points off
if 0 != ret.returncode:
print('compile error')
summary['score'] = 80
summary['comment'].append('late')
continue
# Wow! it compiles!!
# Totally N*2 test cases, you get 1 point for each successful test.
# Finally the N will be normalized to 20.
pts = 0
for x, y in zip(X_test, y_test):
# feed input and grab output from the program
pipe = Popen('./hw1', stdin=PIPE, stdout=PIPE)
inputs = ' '.join(np.char.mod('%d', x))
try:
out = pipe.communicate(input=inputs.encode('utf8'), timeout=2)
except TimeoutExpired:
pipe.kill()
print('timeout', end=' ', flush=True)
summary['comment'].append('timeout')
damnit.append(summary)
break
out = out[0].decode('utf8')
matches = re.findall(args.re_float, out)
results = [float(num) for num in matches]
fact, stdev = y
f0, f1 = False, False
for tmp in results:
if np.isclose(tmp, fact, rtol=0.01):
f0 = True
if np.isclose(tmp, stdev, rtol=0.01):
f1 = True
pts += f0 + f1
pts = int(pts / 2. / args.n_test * 10)
summary['score'] += pts
print('{}'.format(summary['score']))
summaries.append(summary)
with open('hw1.csv', 'w') as w:
for itm in summaries:
w.write('{0},{1},{2}\n'.format(itm['name'], itm['score'],
' '.join(itm['comment'])))
with open('damnit.txt', 'w') as w:
for itm in damnit:
w.write('{0},{1}\n'.format(itm['name'], ' '.join(itm['comment'])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment