This gist contains all the grading script for COMP2710 2019 Spring session.
Last active
June 4, 2019 18:56
-
-
Save gongzhitaao/508b4cfd99cb93353ee34bacdbd24529 to your computer and use it in GitHub Desktop.
COMP 2710 2019 Spring Grading Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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']))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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