├── .gitignore ├── data_gen.py ├── dsl.py ├── dsl_test.py ├── neural_net_model.py └── program.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | *.un~ 4 | *.dat 5 | -------------------------------------------------------------------------------- /data_gen.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys, pickle 4 | 5 | from dsl import FUNCs, Lambdas 6 | from program import Program, Step 7 | 8 | PROGRAMs = [] 9 | 10 | def save(f_path): 11 | """ 12 | Save data to a file 13 | """ 14 | global DEBUG 15 | with open(f_path, 'w+') as f: 16 | if DEBUG: 17 | f.writelines(map(lambda x: str(x)[1:-1]+'\n', PROGRAMs)) 18 | else: 19 | f.writelines(pickle.dumps(PROGRAMs)) 20 | print "Generated programs has been saved at %s" % f_path 21 | 22 | def search_next(cur, program, fo_remain, ho_remain, target_len): 23 | if len(program) == target_len: 24 | p = Program() 25 | for s in program: 26 | p.append_step(Step(*s)) 27 | PROGRAMs.append(p) 28 | # print p 29 | return 30 | else: 31 | valid_fo_funcs = filter(lambda x: FUNCs['FO'][x][1][0] == cur[2] \ 32 | if len(FUNCs['FO'][x][1]) == 1 \ 33 | else FUNCs['FO'][x][1][1] == cur[2], fo_remain) 34 | # len(FUNCs['HO'][x][1]) == 2 \ and 35 | valid_ho_funcs = filter(lambda x: FUNCs['HO'][x][1][1] == cur[2], ho_remain) 36 | for func in valid_fo_funcs: 37 | search_next(FUNCs['FO'][func], \ 38 | program+[(func,)], \ 39 | filter(lambda x: x!=func, valid_fo_funcs), \ 40 | valid_ho_funcs, \ 41 | target_len) 42 | for func in valid_ho_funcs: 43 | for lambs in filter(lambda x: (Lambdas[x][3], Lambdas[x][2])\ 44 | ==FUNCs['HO'][func][1][0], \ 45 | [l for l in Lambdas]): 46 | search_next(FUNCs['HO'][func], \ 47 | program+[(func, lambs)], \ 48 | valid_fo_funcs, \ 49 | filter(lambda x: x!=func, valid_ho_funcs), \ 50 | target_len) 51 | 52 | def main(length, f_path): 53 | print "Generating programs whose length is %d..." % length 54 | fo_funcs = [func for func in FUNCs['FO']] 55 | ho_funcs = [func for func in FUNCs['HO']] 56 | for func in fo_funcs: 57 | search_next(FUNCs['FO'][func], \ 58 | [(func,)], \ 59 | filter(lambda x: x!=func, fo_funcs), \ 60 | ho_funcs, \ 61 | length) 62 | for func in ho_funcs: 63 | for lambs in filter(lambda x: (Lambdas[x][3], Lambdas[x][2])\ 64 | ==FUNCs['HO'][func][1][0], \ 65 | [l for l in Lambdas]): 66 | search_next(FUNCs['HO'][func], \ 67 | [(func, lambs)], \ 68 | fo_funcs, \ 69 | filter(lambda x: x!=func, ho_funcs), \ 70 | length) 71 | save(f_path) 72 | print "Prepare input-output for programs..." 73 | no = 0 74 | for program in PROGRAMs: 75 | print 'No %d' % no 76 | no += 1 77 | # TODO: generate through forword direction 78 | print 'Samples: %s\n' % program.generate_func_in() 79 | 80 | if __name__ == '__main__': 81 | if len(sys.argv) < 2: 82 | print "Usage: python data_gen.py $Length[ $File $DEBUG]\n" +\ 83 | "Param $Length: the length of programe\n" +\ 84 | "Param $File: the path of file to save\n" +\ 85 | "Param $DEBUG: True or False\n" 86 | sys.exit(1) 87 | 88 | f_path = './generated_data.dat' \ 89 | if len(sys.argv)<3 or sys.argv[2]=='-' \ 90 | else sys.argv[2] 91 | global DEBUG 92 | DEBUG = True \ 93 | if len(sys.argv)<4 or sys.argv[3]=='-' else \ 94 | sys.argv[3]=='True' 95 | main(int(sys.argv[1]), f_path) 96 | 97 | -------------------------------------------------------------------------------- /dsl.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random, math 4 | 5 | def SCANL1(f, v): 6 | if len(v) > 0: 7 | y = [v[0]] * len(v) 8 | for i in range(1, len(v)): 9 | y[i] = f(y[i-1], v[i]) 10 | return y 11 | else: 12 | return None 13 | 14 | # 0 -> int, 1 -> [int], 2 -> bool, 3 -> lambda(int), 4 -> lambda(int, int) 15 | TYPE = ['int', '[int]', 'bool'] 16 | 17 | # [func, input type, output type] 18 | FUNCs = { 19 | # First Order 20 | 'FO': { 21 | 'HEAD': [lambda v: v[0] if len(v)>0 else None, (1,), 0], 22 | 'LAST': [lambda v: v[-1] if len(v)>0 else None, (1,), 0], 23 | 'TAKE': [lambda n, v: v[:n], (0, 1), 1], 24 | 'DROP': [lambda n, v: v[n:], (0, 1), 1], 25 | 'ACCESS': [lambda n, v: v[n] if n>=0 and len(v)>n else None, (0, 1), 0], 26 | 'MINIMUM': [lambda v: min(v) if len(v)>0 else None, (1,), 0], 27 | 'MAXIMUM': [lambda v: max(v) if len(v)>0 else None, (1,), 0], 28 | 'REVERSE': [lambda v: list(reversed(v)), (1,), 1], 29 | 'SORT': [lambda v: sorted(v), (1,), 1], 30 | 'SUM': [lambda v: sum(v), (1,), 0], 31 | }, 32 | # High Order, lambda ==> (lambda type, output type) 33 | 'HO': { 34 | 'MAP': [lambda f, v: [f(x) for x in v], ((3, 0), 1), 1], 35 | 'FILTER': [lambda f, v: [x for x in v if f(x)], ((3, 2), 1), 1], 36 | 'COUNT': [lambda f, v: len([x for x in v if f(x)]), ((3, 2), 1), 0], 37 | 'ZIPWITH': [lambda f, v1, v2: [f(x, y) for x, y in zip(v1, v2)], ((4, 0), 1, 1), 1], 38 | 'SCANL1': [SCANL1, ((4, 0), 1), 1] 39 | } 40 | } 41 | 42 | # [lambda, input type, output type, lambda type] 43 | # Lambdas 44 | Lambdas = { 45 | '(+1)': [lambda x: x+1, (0,), 0, 3], 46 | '(-1)': [lambda x: x-1, (0,), 0, 3], 47 | '(*2)': [lambda x: x*2, (0,), 0, 3], 48 | '(/2)': [lambda x: x/2, (0,), 0, 3], 49 | '(*(-1))': [lambda x: x*(-1), (0,), 0, 3], 50 | '(**2)': [lambda x: x**2, (0,), 0, 3], 51 | '(*3)': [lambda x: x*3, (0,), 0, 3], 52 | '(/3)': [lambda x: x/3, (0,), 0, 3], 53 | '(*4)': [lambda x: x*4, (0,), 0, 3], 54 | '(/4)': [lambda x: x/4, (0,), 0, 3], 55 | '(>0)': [lambda x: x>0, (0,), 2, 3], 56 | '(<0)': [lambda x: x<0, (0,), 2, 3], 57 | '(%2==0)': [lambda x: x%2==0, (0,), 2, 3], 58 | '(%2==1)': [lambda x: x%2==1, (0,), 2, 3], 59 | '(+)': [lambda x, y: x+y, (0, 0), 0, 4], 60 | '(-)': [lambda x, y: x-y, (0, 0), 0, 4], 61 | '(*)': [lambda x, y: x*y, (0, 0), 0, 4], 62 | 'MIN': [lambda x, y: x if xy else y, (0, 0), 0, 4], 64 | } 65 | 66 | # Decorators 67 | def oddeven(func): 68 | def wrapper(*args, **kwargs): 69 | g_list = func(*args, **kwargs) 70 | if kwargs['oddeven'] == 0: 71 | return filter(lambda x: x%2==0, g_list) 72 | elif kwargs['oddeven'] == 1: 73 | return filter(lambda x: x%2==1, g_list) 74 | else: 75 | return g_list 76 | return wrapper 77 | 78 | def reverse(func): 79 | def wrapper(*args, **kwargs): 80 | g_list = func(*args, **kwargs) 81 | return FUNCs['FO']['REVERSE'][0](g_list) \ 82 | if kwargs['_reversed'] else g_list 83 | return wrapper 84 | 85 | def gcd(func): 86 | def wrapper(*args, **kwargs): 87 | g_list = func(*args, **kwargs) 88 | gcd = kwargs['gcd'] 89 | return [a*gcd for a in g_list] if gcd != 1 else g_list 90 | return wrapper 91 | 92 | def sign(func): 93 | def wrapper(*args, **kwargs): 94 | g_list = func(*args, **kwargs) 95 | if kwargs['sign'] == 1: 96 | return [-n if n<0 else n for n in filter(lambda x: x!=0, g_list)] 97 | elif kwargs['sign'] == -1: 98 | return [-n if n>0 else n for n in filter(lambda x: x!=0, g_list)] 99 | elif kwargs['sign'] == 0: 100 | return [0] 101 | else: 102 | return g_list 103 | return wrapper 104 | 105 | # API functions 106 | @gcd 107 | @reverse 108 | @oddeven 109 | @sign 110 | def initial_list(**kwargs): 111 | ordered = kwargs['ordered'] 112 | return _gen_ordered_list() if ordered else _gen_list() 113 | # return [a*gcd for a in gen_list] if gcd != 1 else gen_list 114 | 115 | def initial_int(gcd): 116 | return random.randint(-100, 100)*gcd 117 | 118 | def key_of_attr(): 119 | keys = [] 120 | keys.extend(Lambdas.keys()) 121 | keys.extend(FUNCs['FO'].keys()) 122 | keys.extend(FUNCs['HO'].keys()) 123 | return keys 124 | 125 | # Implement functions 126 | def _gen_ordered_list(min_=None, max_=None, length=None): 127 | l = length-1 if length is not None \ 128 | else random.randint(5, 10) 129 | if min_ is not None and max_ is None: 130 | start = min_ 131 | end = start + l 132 | elif max_ is not None and min_ is None: 133 | end = max_ 134 | start = end - l 135 | elif max_ is not None and min_ is not None: 136 | start = min_ 137 | end = max_ 138 | else: 139 | start = random.randint(-10, 10) 140 | end = start + l 141 | return range(start, end+1) 142 | 143 | def _gen_list(min_=None, max_=None): 144 | if min_ is not None and max_ is None: 145 | low_end = min_ 146 | high_end = min_ + 20 147 | elif min_ is None and max_ is not None: 148 | high_end = max_ 149 | low_end = max_ - 20 150 | elif min_ is not None and max_ is not None: 151 | if min_ >= max_: 152 | raise ValueError('max_ must bigger than min_') 153 | low_end = min_ 154 | high_end = max_ 155 | else: 156 | low_end = -10 157 | high_end = 10 158 | 159 | length = random.randint(5, 10) 160 | gen_list = [random.randint(low_end-1, high_end-1) \ 161 | for i in xrange(length)] 162 | gen_list[random.randint(0, len(gen_list)-1)] = low_end \ 163 | if min_ is not None else high_end 164 | return gen_list 165 | 166 | def ReHEAD(n, gcd=1, ordered=False, **kwargs): 167 | gen_list = _gen_ordered_list(min_=n/gcd) \ 168 | if ordered else _gen_list() 169 | if gcd != 1: 170 | gen_list = map(lambda x: x*gcd, gen_list) 171 | gen_list[0] = n 172 | return gen_list 173 | 174 | def ReLAST(n, gcd=1, ordered=False, **kwargs): 175 | gen_list = _gen_ordered_list(max_=n/gcd) \ 176 | if ordered else _gen_list() 177 | if gcd != 1: 178 | gen_list = map(lambda x: x*gcd, gen_list) 179 | gen_list[-1] = n 180 | return gen_list 181 | 182 | def ReTAKE(v, gcd=1, ordered=False, **kwargs): 183 | gen_list = _gen_ordered_list(min_=v[-1]/gcd) \ 184 | if ordered else _gen_list() 185 | if gcd != 1: 186 | gen_list = map(lambda x: x*gcd, gen_list) 187 | return len(v), v + gen_list[1:] 188 | 189 | def ReDROP(v, gcd=1, ordered=False, **kwargs): 190 | gen_list = _gen_ordered_list(max_=v[0]/gcd) \ 191 | if ordered else _gen_list() 192 | if gcd != 1: 193 | gen_list = map(lambda x: x*gcd, gen_list) 194 | return len(gen_list)-1, gen_list[:-1] + v 195 | 196 | def ReACCESS(n, gcd=1, ordered=False, **kwargs): 197 | if ordered: 198 | gen_list1 = _gen_ordered_list(max_=n/gcd, \ 199 | length=random.randint(3, 5)) 200 | gen_list2 = _gen_ordered_list(min_=n/gcd, \ 201 | length=random.randint(3, 5)) 202 | idx, gen_list = len(gen_list1)-1, gen_list1+gen_list2[1:] 203 | else: 204 | gen_list = _gen_list() 205 | idx = random.randint(0, len(gen_list)-1) 206 | if gcd != 1: 207 | gen_list = map(lambda x: x*gcd, gen_list) 208 | gen_list[idx] = n 209 | return idx, gen_list 210 | 211 | def ReMINIMUM(n, gcd=1, ordered=False, **kwargs): 212 | gen_list = _gen_ordered_list(min_=n/gcd) \ 213 | if ordered else _gen_list(min_=n/gcd) 214 | if gcd != 1: 215 | gen_list = map(lambda x: x*gcd, gen_list) 216 | return gen_list 217 | 218 | def ReMAXIMUM(n, gcd=1, ordered=False, **kwargs): 219 | gen_list = _gen_ordered_list(max_=n/gcd) \ 220 | if ordered else _gen_list(max_=n/gcd) 221 | if gcd != 1: 222 | gen_list = map(lambda x: x*gcd, gen_list) 223 | return gen_list 224 | 225 | def ReREVERSE(v, **kwargs): 226 | return list(reversed(v)) 227 | 228 | def ReSORT(v, **kwargs): 229 | random.shuffle(v) 230 | return v 231 | 232 | def ReSUM(n, gcd=1, ordered=False, **kwargs): 233 | gen_list = [] 234 | n /= gcd 235 | negative = False 236 | if n < 0: 237 | n = -n 238 | negative = True 239 | for i in xrange(n): 240 | if i <= n: 241 | gen_list.append(i) 242 | n -= i 243 | else: 244 | break 245 | gen_list.append(n) 246 | if negative: 247 | gen_list = map(lambda x: -x, gen_list) 248 | for i in xrange(2): 249 | x = random.randint(-10, 10) 250 | gen_list.extend([x, -x]) 251 | if gcd != 1: 252 | gen_list = map(lambda x: x*gcd, gen_list) 253 | if ordered: 254 | gen_list = sorted(gen_list) 255 | else: 256 | random.shuffle(gen_list) 257 | return gen_list 258 | 259 | def ReFilter_positive(v, gcd=1, ordered=False): 260 | l = random.randint(3, 7) 261 | gen_list = v + [random.randint(-20, 0)*gcd for i in xrange(l)] 262 | if ordered: 263 | gen_list = sorted(gen_list) 264 | else: 265 | random.shuffle(gen_list) 266 | return gen_list 267 | 268 | def ReFilter_negative(v, gcd=1, ordered=False): 269 | l = random.randint(3, 7) 270 | gen_list = v + [random.randint(0, 20)*gcd for i in xrange(l)] 271 | if ordered: 272 | gen_list = sorted(gen_list) 273 | else: 274 | random.shuffle(gen_list) 275 | return gen_list 276 | 277 | ODD_VECTOR = range(-99, 101, 2) 278 | def ReFilter_even(v, gcd=1, ordered=False): 279 | l = random.randint(3, 7) 280 | start = random.randint(0, 99-l) 281 | gen_list = v + [i*gcd for i in ODD_VECTOR[start:start+l]] 282 | if ordered: 283 | gen_list = sorted(gen_list) 284 | else: 285 | random.shuffle(gen_list) 286 | return gen_list 287 | 288 | EVEN_VECTOR = range(-100, 100, 2) 289 | def ReFilter_odd(v, gcd=1, ordered=False): 290 | l = random.randint(3, 7) 291 | start = random.randint(0, 99-l) 292 | gen_list = v + [i*gcd for i in EVEN_VECTOR[start:start+l]] 293 | if ordered: 294 | gen_list = sorted(gen_list) 295 | else: 296 | random.shuffle(gen_list) 297 | return gen_list 298 | 299 | def ReFilter(f, v, gcd=1, ordered=False, **kwargs): 300 | if f == '(>0)': 301 | return ReFilter_positive(v, gcd, ordered) 302 | elif f == '(<0)': 303 | return ReFilter_negative(v, gcd, ordered) 304 | elif f == '(%2==0)': 305 | return ReFilter_even(v, gcd, ordered) 306 | elif f == '(%2==1)': 307 | return ReFilter_odd(v, gcd, ordered) 308 | else: 309 | raise ValueError('Bad lambda: %s', f) 310 | 311 | def ReMap(f, v, **kwargs): 312 | if Lambdas[f][2] == 2 or len(Lambdas[f][1]) > 1: 313 | raise ValueError('Bad lambda: %s', f) 314 | return map(ReLambdas[f], v) 315 | 316 | def ReCOUNT(f, n, gcd=1, ordered=False, **kwargs): 317 | if f == '(>0)': 318 | gen_list = range(1, n+1) 319 | gen_list.extend([random.randint(-10, 0) for i in range(5)]) 320 | elif f == '(<0)': 321 | gen_list = [-i for i in range(1, n+1)] 322 | gen_list.extend([random.randint(0, 10) for i in range(5)]) 323 | elif f == '(%2==0)': 324 | gen_list = [i for i in range(0, 2*n, 2)] 325 | gen_list.extend([ODD_VECTOR[random.randint(0, 99)] for i in range(5)]) 326 | elif f == '(%2==1)': 327 | gen_list = [i for i in range(1, 2*n+1, 2)] 328 | gen_list.extend([EVEN_VECTOR[random.randint(0, 99)] for i in range(5)]) 329 | else: 330 | raise ValueError('Bad lambda: %s', f) 331 | if gcd > 1: 332 | gen_list = map(lambda x: x*gcd, gen_list) 333 | if ordered: 334 | gen_list = sorted(gen_list) 335 | else: 336 | random.shuffle(gen_list) 337 | return gen_list 338 | 339 | def ReZIPWITH(f, v, gcd=1, **kwargs): 340 | if len(Lambdas[f][1]) < 2: 341 | raise ValueError('Bad lambda: %s', f) 342 | gen_list1 = [] 343 | gen_list2 = [] 344 | for e in v: 345 | a, b = ReLambdas[f](e, gcd) 346 | gen_list1.append(a) 347 | gen_list2.append(b) 348 | return gen_list1, gen_list2 349 | 350 | def ReSCANL1(f, v, gcd=1, **kwargs): 351 | y = [v[-1]] * len(v) 352 | y[0] = v[0] 353 | if f == '(+)': 354 | for i in range(1, len(v))[::-1]: 355 | y[i] = v[i] - v[i-1] 356 | elif f == '(-)': 357 | for i in range(1, len(v))[::-1]: 358 | y[i] = v[i-1] - v[i] 359 | elif f == '(*)': 360 | for i in range(1, len(v))[::-1]: 361 | y[i] = v[i] / v[i-1] 362 | elif f == 'MIN': 363 | for i in range(1, len(v))[::-1]: 364 | if v[i] == v[i-1]: 365 | y[i] = v[i] + random.randint(0, 10) 366 | else: 367 | y[i] = v[i] 368 | elif f == 'MAX': 369 | for i in range(1, len(v))[::-1]: 370 | if v[i] == v[i-1]: 371 | y[i] = v[i] - random.randint(0, 10) 372 | else: 373 | y[i] = v[i] 374 | else: 375 | raise ValueError('Bad lambda: %s', f) 376 | return y 377 | 378 | ReFUNCs = { 379 | 'FO': { 380 | 'HEAD': ReHEAD, 381 | 'LAST': ReLAST, 382 | 'TAKE': ReTAKE, 383 | 'DROP': ReDROP, 384 | 'ACCESS': ReACCESS, 385 | 'MINIMUM': ReMINIMUM, 386 | 'MAXIMUM': ReMAXIMUM, 387 | 'REVERSE': ReREVERSE, 388 | 'SORT': ReSORT, 389 | 'SUM': ReSUM 390 | }, 391 | 'HO': { 392 | 'FILTER': ReFilter, 393 | 'MAP': ReMap, 394 | 'COUNT': ReCOUNT, 395 | 'ZIPWITH': ReZIPWITH, 396 | 'SCANL1': ReSCANL1 397 | } 398 | } 399 | 400 | def ReLambda_add(n, gcd=1): 401 | n /= gcd 402 | a = random.randint(n-20, n) 403 | b = n - a 404 | if gcd > 1: 405 | a *= gcd 406 | b *= gcd 407 | return a, b 408 | 409 | def ReLambda_del(n, gcd=1): 410 | n /= gcd 411 | a = random.randint(-10, 10) 412 | b = n + a 413 | if gcd > 1: 414 | a *= gcd 415 | b *= gcd 416 | return b, a 417 | 418 | def ReLambda_mul(n, gcd=1): 419 | n /= gcd 420 | while True: 421 | a = random.randint(1, 10) 422 | if n%a == 0: 423 | break 424 | b = n / a 425 | if gcd > 1: 426 | b *= gcd 427 | return a, b 428 | 429 | def ReLambda_min(n, gcd=1): 430 | if random.randint(0, 1) == 0: 431 | a, b = (n + random.randint(0, 5)) * gcd, n 432 | else: 433 | b, a = (n + random.randint(0, 5)) * gcd, n 434 | return a, b 435 | 436 | def ReLambda_max(n, gcd=1): 437 | if random.randint(0, 1) == 0: 438 | a, b = (n - random.randint(0, 5)) * gcd, n 439 | else: 440 | b, a = (n - random.randint(0, 5)) * gcd, n 441 | return a, b 442 | 443 | ReLambdas = { 444 | '(+1)': lambda x: x-1, 445 | '(-1)': lambda x: x+1, 446 | '(*2)': lambda x: x/2, 447 | '(/2)': lambda x: x*2, 448 | '(*(-1))': lambda x: x*(-1), 449 | '(**2)': lambda x: int(math.sqrt(x)), 450 | '(*3)': lambda x: x/3, 451 | '(/3)': lambda x: x*3, 452 | '(*4)': lambda x: x/4, 453 | '(/4)': lambda x: x*4, 454 | # '(>0)': [lambda x: x>0, (0,), 2, 3], 455 | # '(<0)': [lambda x: x<0, (0,), 2, 3], 456 | # '(%2==0)': [lambda x: x%2==0, (0,), 2, 3], 457 | # '(%2==1)': [lambda x: x%2==1, (0,), 2, 3], 458 | '(+)': ReLambda_add, 459 | '(-)': ReLambda_del, 460 | '(*)': ReLambda_mul, 461 | 'MIN': ReLambda_min, 462 | 'MAX': ReLambda_max, 463 | } 464 | 465 | -------------------------------------------------------------------------------- /dsl_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding=utf-8 -*- 2 | 3 | import random 4 | from dsl import FUNCs, Lambdas, ReFUNCs, ReLambdas 5 | 6 | vector = [4, -10, 3, 7, -9, 2, -1, -2] 7 | ordered_vector = range(-4, 4) 8 | value = 3 9 | 10 | def head_test(): 11 | ret = FUNCs['FO']['HEAD'][0](vector) 12 | print '%s, %d, %s' % (vector, ret, ReFUNCs['FO']['HEAD'](ret)) 13 | ret = FUNCs['FO']['HEAD'][0](ordered_vector) 14 | print '%s, %d, %s' % (ordered_vector, ret, ReFUNCs['FO']['HEAD'](ret, gcd=2, ordered=True)) 15 | 16 | def last_test(): 17 | ret = FUNCs['FO']['LAST'][0](vector) 18 | print '%s, %d, %s' % (vector, ret, ReFUNCs['FO']['LAST'](ret)) 19 | ret = FUNCs['FO']['LAST'][0](ordered_vector) 20 | print '%s, %d, %s' % (ordered_vector, ret, ReFUNCs['FO']['LAST'](ret, gcd=3, ordered=True)) 21 | 22 | def take_test(): 23 | ret = FUNCs['FO']['TAKE'][0](value, vector) 24 | print '%s, %s, %s' % (vector, ret, ReFUNCs['FO']['TAKE'](ret)) 25 | ret = FUNCs['FO']['TAKE'][0](value, ordered_vector) 26 | print '%s, %s, %s' % (ordered_vector, ret, ReFUNCs['FO']['TAKE'](ret, gcd=2, ordered=True)) 27 | 28 | def drop_test(): 29 | ret = FUNCs['FO']['DROP'][0](value, vector) 30 | print '%s, %s, %s' % (vector, ret, ReFUNCs['FO']['DROP'](ret)) 31 | ret = FUNCs['FO']['DROP'][0](value, ordered_vector) 32 | print '%s, %s, %s' % (ordered_vector, ret, ReFUNCs['FO']['DROP'](ret, gcd=2, ordered=True)) 33 | 34 | def access_test(): 35 | ret = FUNCs['FO']['ACCESS'][0](value, vector) 36 | print '(%d, %s), %d, %s' % (value, vector, ret, ReFUNCs['FO']['ACCESS'](ret)) 37 | ret = FUNCs['FO']['ACCESS'][0](value, ordered_vector) 38 | print '(%d, %s), %d, %s' % (value, ordered_vector, ret, ReFUNCs['FO']['ACCESS'](ret, gcd=2, ordered=True)) 39 | 40 | def minimum_test(): 41 | ret = FUNCs['FO']['MINIMUM'][0](vector) 42 | print '%s, %d, %s' % (vector, ret, ReFUNCs['FO']['MINIMUM'](ret)) 43 | ret = FUNCs['FO']['MINIMUM'][0](ordered_vector) 44 | print '%s, %d, %s' % (ordered_vector, ret, ReFUNCs['FO']['MINIMUM'](ret, gcd=2, ordered=True)) 45 | 46 | def maximum_test(): 47 | ret = FUNCs['FO']['MAXIMUM'][0](vector) 48 | print '%s, %d, %s' % (vector, ret, ReFUNCs['FO']['MAXIMUM'](ret)) 49 | ret = FUNCs['FO']['MAXIMUM'][0](ordered_vector) 50 | print '%s, %d, %s' % (ordered_vector, ret, ReFUNCs['FO']['MAXIMUM'](ret, gcd=3, ordered=True)) 51 | 52 | def reverse_test(): 53 | ret = FUNCs['FO']['REVERSE'][0](vector) 54 | print '%s, %s, %s' % (vector, ret, ReFUNCs['FO']['REVERSE'](ret)) 55 | ret = FUNCs['FO']['REVERSE'][0](ordered_vector) 56 | print '%s, %s, %s' % (ordered_vector, ret, ReFUNCs['FO']['REVERSE'](ret)) 57 | 58 | def sort_test(): 59 | ret = FUNCs['FO']['SORT'][0](vector) 60 | print '%s, %s' % (vector, ret) 61 | print '%s' % ReFUNCs['FO']['SORT'](ret) 62 | 63 | def sum_test(): 64 | for x in [-10, -3, 0, 5, 11]: 65 | print '%d, %s' % (x, ReFUNCs['FO']['SUM'](x)) 66 | for x in [-3, 3, 9]: 67 | print '%d, %s' % (x, \ 68 | ReFUNCs['FO']['SUM'](x, gcd=3, ordered=True)) 69 | 70 | def lambadd_test(): 71 | for i in [-10, -2, 0, 9]: 72 | print "%d=+%s" % (i, ReLambdas['(+)'](i)) 73 | for i in [-9, 9]: 74 | print "%d=+%s" % (i, ReLambdas['(+)'](i, gcd=3)) 75 | 76 | def lambdel_test(): 77 | for i in [-10, -2, 0, 9]: 78 | print "%d=-%s" % (i, ReLambdas['(-)'](i)) 79 | for i in [-9, 9]: 80 | print "%d=-%s" % (i, ReLambdas['(-)'](i, gcd=3)) 81 | 82 | def lambmul_test(): 83 | for i in [-10, -2, 0, 9]: 84 | print "%d=*%s" % (i, ReLambdas['(*)'](i)) 85 | for i in [-9, 9]: 86 | print "%d=*%s" % (i, ReLambdas['(*)'](i, gcd=3)) 87 | 88 | def lambmin_test(): 89 | for i in [-10, -2, 0, 9]: 90 | print "%d, %s" % (i, ReLambdas['MIN'](i)) 91 | for i in [-1, 0, 2]: 92 | print "%d, %s" % (i, ReLambdas['MIN'](i, gcd=2)) 93 | 94 | def lambmax_test(): 95 | for i in [-10, -2, 0, 9]: 96 | print "%d, %s" % (i, ReLambdas['MAX'](i)) 97 | for i in [-1, 0, 2]: 98 | print "%d, %s" % (i, ReLambdas['MAX'](i, gcd=2)) 99 | 100 | def filter_p_test(): 101 | v = range(2, 10, 2) 102 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(>0)'](v)) 103 | v = range(2, 10, 2) 104 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(>0)'](v, gcd=2, ordered=True)) 105 | 106 | def filter_n_test(): 107 | v = range(-20, -10, 2) 108 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(<0)'](v)) 109 | v = range(-20, -10, 2) 110 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(<0)'](v, gcd=2, ordered=True)) 111 | 112 | def filter_e_test(): 113 | v = range(2, 10, 2) 114 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(%2==0)'](v)) 115 | v = range(2, 10, 2) 116 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(%2==0)'](v, ordered=True)) 117 | 118 | def filter_o_test(): 119 | v = range(1, 11, 2) 120 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(%2==1)'](v)) 121 | v = range(1, 11, 2) 122 | print "%s, %s" % (v, ReFUNCs['HO']['FILTER_(%2==1)'](v, gcd=2, ordered=True)) 123 | 124 | def map_test(): 125 | v = range(10) 126 | print "%s%s, %s" % (ReFUNCs['HO']['MAP']('(-1)', v), '(-1)', v) 127 | print "%s%s, %s" % (ReFUNCs['HO']['MAP']('(+1)', v), '(+1)', v) 128 | print "%s%s, %s" % (ReFUNCs['HO']['MAP']('(/2)', v), '(/2)', v) 129 | print "%s%s, %s" % (ReFUNCs['HO']['MAP']('(*(-1))', v), '(*(-1))', v) 130 | v = [1, 4, 9, 16] 131 | print "%s%s, %s" % (ReFUNCs['HO']['MAP']('(**2)', v), '(**2)', v) 132 | 133 | def count_test(): 134 | n = 5 135 | print "%d, %s, %s" % (n, '(>0)', ReFUNCs['HO']['COUNT']('(>0)', n)) 136 | print "%d, %s, %s" % (n, '(<0)', ReFUNCs['HO']['COUNT']('(<0)', n)) 137 | print "%d, %s, %s" % (n, '(%2==0)', ReFUNCs['HO']['COUNT']('(%2==0)', n)) 138 | print "%d, %s, %s" % (n, '(%2==1)', ReFUNCs['HO']['COUNT']('(%2==1)', n, gcd=3, ordered=True)) 139 | 140 | def zipwith_test(): 141 | res = range(10, 20) 142 | ret = ReFUNCs['HO']['ZIPWITH']('(+)', res) 143 | print "%s%s%s=%s" % (ret[0], '(+)', ret[1], res) 144 | ret = ReFUNCs['HO']['ZIPWITH']('(-)', res, gcd = 2) 145 | print "%s%s%s=%s" % (ret[0], '(-)', ret[1], res) 146 | ret = ReFUNCs['HO']['ZIPWITH']('(*)', res) 147 | print "%s%s%s=%s" % (ret[0], '(*)', ret[1], res) 148 | ret = ReFUNCs['HO']['ZIPWITH']('MIN', res) 149 | print "%s%s%s=%s" % (ret[0], 'MIN', ret[1], res) 150 | ret = ReFUNCs['HO']['ZIPWITH']('MAX', res) 151 | print "%s%s%s=%s" % (ret[0], 'MAX', ret[1], res) 152 | 153 | def scanl1_test(): 154 | v = range(10, 20) 155 | random.shuffle(v) 156 | print v 157 | ret = FUNCs['HO']['SCANL1'][0](Lambdas['MAX'][0], v) 158 | print ret 159 | ret = ReFUNCs['HO']['SCANL1']('MAX', ret) 160 | print ret 161 | print FUNCs['HO']['SCANL1'][0](Lambdas['MAX'][0], ret) 162 | 163 | TEST_FUNCs = { 164 | 'head': head_test, 165 | 'last': last_test, 166 | 'take': take_test, 167 | 'drop': drop_test, 168 | 'access': access_test, 169 | 'minimum': minimum_test, 170 | 'maximum': maximum_test, 171 | 'reverse': reverse_test, 172 | 'sort': sort_test, 173 | 'sum': sum_test, 174 | 'lambadd': lambadd_test, 175 | 'lambdel': lambdel_test, 176 | 'lambmul': lambmul_test, 177 | 'lambmin': lambmin_test, 178 | 'lambmax': lambmax_test, 179 | 'filter_p': filter_p_test, 180 | 'filter_n': filter_n_test, 181 | 'filter_e': filter_e_test, 182 | 'filter_o': filter_o_test, 183 | 'map': map_test, 184 | 'count': count_test, 185 | 'zipwith': zipwith_test, 186 | 'scanl1': scanl1_test, 187 | } 188 | 189 | if __name__ == '__main__': 190 | import sys 191 | if len(sys.argv) < 2: 192 | print "Usage:\n" + \ 193 | "dsl_test.py $FUNC\n" + \ 194 | "param $FUNC: the name of function" 195 | sys.exit(1) 196 | 197 | TEST_FUNCs[sys.argv[1]]() 198 | 199 | -------------------------------------------------------------------------------- /neural_net_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # NOTE: need python 3.5 and tenflow 1.01 3 | 4 | import tensorflow as tf 5 | import numpy as np 6 | import pickle 7 | 8 | # nn's paramters 9 | sample_num = 5 # number of input-output samples for each program 10 | type_length = 2 # length of one-hot vector for input-output type 11 | array_length = 20 # NOTE: L in paper 12 | embedding_index = 513 # NOTE: [-256, 255] + None 13 | embedding_width = 20 # NOTE: E in paper 14 | hidden_width_1 = 2*(type_length+array_length*embedding_width) 15 | hidden_width_2 = 256 # NOTE: K in paper 16 | output_width = 34 # NOTE: C in paper 17 | 18 | # training parameters 19 | learning_rate = 0.01 20 | training_epochs = 20 21 | batch_size = 256 22 | display_step = 1 23 | examples_to_show = 10 24 | 25 | weights = { 26 | # 'encoder_embedding': tf.Variable(tf.random_normal([array_length, embedding_width])), 27 | 'encoder_h1': tf.Variable(tf.random_normal([hidden_width_1, hidden_width_2])), 28 | 'encoder_h2': tf.Variable(tf.random_normal([hidden_width_2, hidden_width_2])), 29 | 'encoder_h3': tf.Variable(tf.random_normal([hidden_width_2, hidden_width_2])), 30 | 'decoder': tf.Variable(tf.random_normal([hidden_width_2, output_width])) 31 | } 32 | 33 | biases = { 34 | 'encoder_b1': tf.Variable(tf.random_normal([hidden_width_2])), 35 | 'encoder_b2': tf.Variable(tf.random_normal([hidden_width_2])), 36 | 'encoder_b3': tf.Variable(tf.random_normal([hidden_width_2])), 37 | 'decoder': tf.Variable(tf.random_normal([output_width])) 38 | } 39 | 40 | def _prev_process(input_type, input_array, output_type, output_array): 41 | """ 42 | :param input_type: integer value, 0 --> int, 1 --> [int] 43 | :param input_array: integer or list based on input_type 44 | :param output_type: same as input_type 45 | :param output_array: same as output_array 46 | :return: a vector concated by input_type, input_array, output_type, output_array 47 | """ 48 | # TODO: train an embedding layer 49 | embedding = tf.Variable(tf.random_normal([embedding_index, embedding_width])) 50 | 51 | def to_array(v, length=20): 52 | if type(v) == int: 53 | v = [v] 54 | if type(v) != list: 55 | raise TypeError('Must be a list, %s is given' % type(v)) 56 | if len(v) > array_length: 57 | raise TypeError('Must be shorter than %d, %d is given' \ 58 | % (array_length, len(v))) 59 | ret = [0] * (array_length - len(v)) 60 | # 0 is Null's index, so we need add 257 to map -256 to 1 61 | ret.extend(v, map(lambda x: x+257, v)) 62 | return np.array(ret) 63 | 64 | def type_to_one_hot(t): 65 | """ 66 | :return: vector, [int, [int]], e.g. [1.0, 0.0] means an int 67 | """ 68 | if type(t) != int: 69 | raise TypeError('Must be an int, %s is given' % type(v)) 70 | ret = [.0] * type_length 71 | ret[t] = 1. 72 | return np.array(ret) 73 | 74 | i_type = type_to_one_hot(input_type) 75 | input_data = to_array(input_array, array_length) 76 | inputs = tf.reshape(tf.nn.embedding_lookup(embedding, input_data), \ 77 | [input_array*array_length]) 78 | 79 | o_type = type_to_one_hot(output_type) 80 | output_data = to_array(output_array, array_length) 81 | outputs = tf.reshape(tf.nn.embedding_lookup(embedding, output_data), \ 82 | [input_array*array_length]) 83 | 84 | return np.concatenate([i_type, inputs, o_type, outputs]) 85 | 86 | def prev_process(samples): 87 | """ 88 | :param samples: 3-D python array, [batch_size, sample_num, hidden_width_1] 89 | :return: 3-D Tensor, [batch_size, sample_num, hidden_width_1] 90 | """ 91 | input_mat = np.array([[_prev_process(*s) for s in ss] for ss in samples]) 92 | return tf.reshape(input_mat, [batch_size, sample_num, hidden_width_1]) 93 | 94 | def __encoder(x): 95 | """ 96 | :param x: vector, with hidden_width_2 dimension 97 | :return: vector, with hidden_width_2 dimension 98 | """ 99 | layer_2 = tf.sigmoid(tf.add(tf.matmul(x, weights['encoder_h1']), \ 100 | biases['encoder_b1'])) 101 | layer_3 = tf.sigmoid(tf.add(tf.matmul(layer_2, weights['encoder_h2']), \ 102 | biases['encoder_b2'])) 103 | layer_4 = tf.sigmoid(tf.add(tf.matmul(layer_3, weights['encoder_h3']), \ 104 | biases['encoder_b3'])) 105 | return layer_4 106 | 107 | def _encoder(x): 108 | """ 109 | :param x: 2-D tensor, shape is [sample_num, hidden_width_1] 110 | :return: 1-D tensor, shape is [hidden_width_2] 111 | """ 112 | layer_5 = tf.map_fn(__encoder, x) 113 | return tf.reduce_mean(layer_5, 0) 114 | 115 | def encoder(x): 116 | """ 117 | :param x: 3-D tensor, shape is [batch_size, sample_num, hidden_width_1] 118 | :return: 2-D tensor, shape is [batch_size, hidden_width_2] 119 | """ 120 | return tf.map_fn(_encoder, x) 121 | 122 | def _decoder(x): 123 | return tf.sigmoid(tf.add(tf.matmul(x, weights['decoder']), \ 124 | biases['decoder'])) 125 | 126 | def decoder(x): 127 | """ 128 | :param x: 2-D tensor, shape is [batch_size, hidden_width_2] 129 | :return: 2-D tensor, shape is [batch_size, output_width] 130 | """ 131 | return tf.map_fn(_decoder, x) 132 | 133 | def input_samples(input_file): 134 | """A generator 135 | :return: [batch_size, 5, 4], [batch_size] 136 | """ 137 | samples = {'x':[], 'y':[]} 138 | with open(input_file, 'r') as fd: 139 | sample = pickle.loads(fd.readline()) 140 | samples['y'].append(sample[1]) 141 | samples['x'].append(sample[2]) 142 | samples.append(pickle.loads(fd.readline())) 143 | if len(samples) == batch_size: 144 | yield samples['x'], samples['y'] 145 | samples = {x:[], y:[]} 146 | 147 | yield samples['x'], samples['y'] 148 | 149 | X = tf.placeholder("float32", [batch_size, sample_num, hidden_width_1]) 150 | Y = tf.placeholder("float32", [batch_size, output_type]) 151 | 152 | def main(input_file): 153 | # construct computing flow 154 | encoder_op = encoder(X) 155 | decoder_op = decoder(encoder_op) 156 | 157 | y_pred = decoder_op 158 | y_true = Y 159 | loss = tf.reduce_mean(-y_true * tf.log(y_pred) - (1-y_true) * tf.log(1-y_pred)) 160 | optimizer = tf.train.RMSPropOptimizer(learning_rate).minimize(loss) 161 | 162 | init = tf.global_variables_initializer() 163 | with tf.Session() as sess: 164 | sess.run(init) 165 | 166 | # train 167 | for epoch in range(training_epochs): 168 | for batch_x, batch_y in input_samples(input_file): 169 | _, c = sess.run([optimizer, loss], feed_dict={\ 170 | X: prev_process(batch_x), \ 171 | Y: batch_y}) 172 | if epoch % display_step == 0: 173 | print("Epoch:", "%04d" % (epoch+1), "cost=", "%.9f" % c) 174 | 175 | print("Optimization Finished!") 176 | 177 | # TODO: Test 178 | 179 | -------------------------------------------------------------------------------- /program.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from dsl import FUNCs, Lambdas, ReFUNCs, ReLambdas, \ 4 | initial_list, initial_int, key_of_attr, TYPE 5 | 6 | class Step(object): 7 | def __init__(self, step_func, step_lambda=None): 8 | self._gcd = 1 9 | self._ordered = False 10 | self._func = step_func 11 | self._lambda = step_lambda 12 | self._multi_param = False 13 | self._reversed = False 14 | self._oddeven = None 15 | self._sign = None 16 | # TODO: sqrt 2? 17 | 18 | if step_lambda == None: 19 | self._func_type = 'FO' 20 | self._step_func = FUNCs['FO'][step_func] 21 | self._step_refunc = ReFUNCs['FO'][step_func] 22 | if step_func == 'SORT': 23 | self._ordered = True 24 | elif step_func == 'REVERSE': 25 | self._reversed = True 26 | if len(self._step_func[1]) > 1: 27 | self._multi_param = True 28 | else: 29 | self._func_type = 'HO' 30 | self._step_func = FUNCs['HO'][step_func] 31 | self._step_lambda = Lambdas[step_lambda] 32 | self._step_refunc = ReFUNCs['HO'][step_func] 33 | if step_lambda == '(*2)': 34 | self._gcd = 2 35 | elif step_lambda == '(*3)': 36 | self._gcd = 3 37 | elif step_lambda == '(*4)': 38 | self._gcd = 4 39 | elif step_lambda == '(%2==0)': 40 | self._oddeven = 0 41 | elif step_lambda == '(%2==1)': 42 | self._oddeven = 1 43 | elif step_lambda == '(>0)': 44 | self._sign = 1 45 | elif step_lambda == '(<0)': 46 | self._sign = -1 47 | if len(self._step_func[1]) > 2: 48 | self._multi_param = True 49 | 50 | def __str__(self): 51 | return "(%s, %s)" % (self._func, self._lambda) 52 | 53 | @property 54 | def funcs(self): 55 | ret = [self._func] 56 | if self._lambda is not None: 57 | ret.append(self._lambda) 58 | return ret 59 | 60 | def _type_check(self, var, tar_type): 61 | src_type = -1 62 | if type(var) == int: 63 | src_type = 0 64 | elif type(var) == list: 65 | if type(var[0]) == int: 66 | src_type = 1 67 | else: 68 | return False 69 | 70 | return True if src_type == tar_type else False 71 | 72 | def step_out(self, *step_in): 73 | """ 74 | Return a step_out based on a step_in 75 | """ 76 | if self._func_type == 'FO' and \ 77 | not self._type_check(step_in[0], \ 78 | self._step_func[1][0]) or \ 79 | self._func_type == 'HO' and \ 80 | not self._type_check(step_in[0], \ 81 | self._step_func[1][1]): 82 | print '%s step in type error' % self._step_func 83 | return None 84 | if self._func_type == 'HO': 85 | return self._step_func[0](self._step_lambda[0], *step_in) 86 | return self._step_func[0](*step_in) 87 | 88 | def step_in(self, step_out, **kwargs): 89 | """ 90 | Return a step_in based on a step_out 91 | """ 92 | if self._func_type == 'FO' and \ 93 | not self._type_check(step_out, \ 94 | self._step_func[2]) or \ 95 | self._func_type == 'HO' and \ 96 | not self._type_check(step_out, \ 97 | self._step_func[2]): 98 | print '%s step out type error' % self._step_func 99 | return None 100 | if self._func_type == 'HO': 101 | return self._step_refunc(self._lambda, step_out) 102 | return self._step_refunc(step_out, **kwargs) 103 | 104 | def step_gcd(self, gcd_now): 105 | """ 106 | Return gcd after this step 107 | """ 108 | return gcd_now*self._gcd 109 | 110 | def step_ordered(self, ordered_now): 111 | """ 112 | Return ordered after this step 113 | """ 114 | return ordered_now or self._ordered 115 | 116 | def step_reveresd(self, reversed_now): 117 | """ 118 | Return ordered after this step, use xor 119 | """ 120 | return reversed_now ^ self._reversed 121 | 122 | def step_oddeven(self, oddeven_now): 123 | # TODO: How to consider previous status 124 | return self._oddeven 125 | 126 | def step_sign(self, sign_now): 127 | """ 128 | -1 means negative 129 | 1 means positive 130 | 0 means zero 131 | """ 132 | if self._sign is None: 133 | return sign_now 134 | if sign_now is None: 135 | return self._sign 136 | if sign_now != self._sign: 137 | return 0 138 | return sign_now 139 | 140 | @property 141 | def multi_param(self): 142 | return self._multi_param 143 | 144 | @property 145 | def param_type(self): 146 | return self._step_func[1] 147 | 148 | @property 149 | def step_output_type(self): 150 | return self._step_func[2] 151 | 152 | class Program(object): 153 | def __init__(self): 154 | # [Step, Step, ...] 155 | self._steps = [] 156 | # [[{'-2': param1, '-1': param2}, result], ...] 157 | self._samples = [] 158 | # {'key2': [['key0', 'key1'], 'key2']} 159 | self._exec_flow = {} 160 | # {'key': 0 or 1} 161 | self._attr = {} 162 | self._attr.fromkeys(key_of_attr(), 0) 163 | self._param_num = 0 164 | 165 | def __str__(self): 166 | return str([str(step) for step in self._steps]) 167 | 168 | def _add_param(self, idx, p_type): 169 | """ 170 | param idx: the index of step use this parameter 171 | return: the index of this parameter 172 | """ 173 | self._param_num += 1 174 | self._exec_flow[str(-self._param_num)] = [None, idx, p_type] 175 | return str(-self._param_num) 176 | 177 | def _add_step(self, idx, prev_idx, p_num=1, p_idx=0): 178 | """ 179 | param idx: the index of step use this parameter 180 | param prev_idx: the index of step before this step 181 | param p_num: the number of p_num 182 | param p_idx: the index of this parameter 183 | """ 184 | if not self._exec_flow.has_key(idx): 185 | self._exec_flow[idx] = [[0]*p_num, None] 186 | self._exec_flow[idx][0][p_idx] = prev_idx 187 | self._exec_flow[prev_idx][1] = idx 188 | 189 | def append_step(self, step): 190 | if type(step) != Step: 191 | raise TypeError('Should be an instance of Step, not %s', type(step)) 192 | self._steps.append(step) 193 | for func in step.funcs: 194 | self._attr[func] = 1 195 | # Update the execution flow 196 | prev_res = None 197 | step_idx = len(self._steps)-1 198 | for f in self._exec_flow.items(): 199 | if f[1][1] is None: 200 | prev_res = f[0] 201 | break 202 | if prev_res is None: 203 | if step.multi_param: 204 | param_num = 2 205 | else: 206 | param_num = 1 207 | for i, p_type in zip(range(param_num), step.param_type): 208 | p_idx = self._add_param(str(step_idx), p_type) 209 | self._add_step(str(step_idx), p_idx, param_num, i) 210 | else: 211 | if step.multi_param: 212 | prev_step = self._steps[int(prev_res)] 213 | pr_type = prev_step.step_output_type 214 | param_num = len(step.param_type) 215 | for pa, i in zip(step.param_type, range(param_num)): 216 | if pr_type == pa: 217 | self._add_step(str(step_idx), prev_res, param_num, i) 218 | else: 219 | self._add_step(str(step_idx), \ 220 | self._add_param(str(step_idx), pa), param_num, i) 221 | else: 222 | self._add_step(str(step_idx), prev_res) 223 | 224 | def _dfs_exec(self, step_now, func_out, **kw): # gcd, ordered, _reversed, oddeven 225 | if step_now == len(self._steps)-1: 226 | if func_out == None: 227 | if self._steps[-1].step_output_type == 0: 228 | func_out = initial_int(self._steps[-1].step_gcd(kw['gcd'])) 229 | init_p = func_out 230 | elif self._steps[-1].step_output_type == 1: 231 | func_out = initial_list(gcd=self._steps[-1].step_gcd(kw['gcd']), \ 232 | ordered=self._steps[-1].step_ordered(kw['ordered']), \ 233 | _reversed=self._steps[-1].step_reveresd(kw['_reversed']), \ 234 | oddeven=self._steps[-1].step_oddeven(kw['oddeven']), \ 235 | sign=self._steps[-1].step_oddeven(kw['sign'])) 236 | # deep copy 237 | init_p = [] 238 | init_p.extend(func_out) 239 | return self._steps[step_now].step_in(init_p, gcd=kw['gcd'], \ 240 | ordered=kw['ordered'], _reversed=kw['_reversed']), [{}, func_out] 241 | _step_in, _out = self._dfs_exec(step_now+1, func_out, \ 242 | gcd=self._steps[step_now].step_gcd(kw['gcd']), \ 243 | ordered=self._steps[step_now].step_ordered(kw['ordered']), \ 244 | _reversed=self._steps[step_now].step_reveresd(kw['_reversed']), \ 245 | oddeven=self._steps[step_now].step_oddeven(kw['oddeven']), \ 246 | sign=self._steps[step_now].step_oddeven(kw['sign'])) 247 | flow = self._exec_flow[str(step_now+1)] 248 | _step_out = None 249 | if type(_step_in) == tuple: 250 | for p, i in zip(flow[0], range(len(flow))): 251 | if int(p) < 0: 252 | _out[0][p] = _step_in[i] 253 | else: 254 | _step_out = _step_in[i] 255 | else: 256 | _step_out = _step_in 257 | # print 'Step: %d, Step in: %s, Out: %s' % (step_now+1, _step_in, _out) 258 | return self._steps[step_now].step_in(_step_out, gcd=kw['gcd'], \ 259 | ordered=kw['ordered'], _reversed=kw['_reversed']), _out 260 | 261 | def generate_func_in(self, func_out=None): 262 | """ 263 | Return a valid input of this program based on the output. 264 | """ 265 | # generate 266 | kw = { 267 | 'gcd': 1, 268 | 'ordered': False, 269 | '_reversed': False, 270 | 'oddeven': None, 271 | 'sign': None 272 | } 273 | for i in range(5): 274 | _step_in, _out = self._dfs_exec(0, func_out, **kw) 275 | if type(_step_in)==tuple: 276 | params = _step_in 277 | else: 278 | params = (_step_in, ) 279 | for param, i in zip(params, range(len(params))): 280 | _out[0][self._exec_flow['0'][0][i]] = param 281 | # print 'Step: %d, Step in: %s, Out: %s' % (0, _step_in, _out) 282 | self._samples.append(_out) 283 | # verify 284 | a, b = self.verify(self._samples) 285 | if a != b: 286 | print str(self) 287 | import pdb 288 | pdb.set_trace() 289 | 290 | return self._samples 291 | 292 | def execute(self, func_in): 293 | """ 294 | Execute this program and return the result. 295 | """ 296 | # check the number of parameters 297 | if len(func_in) != self._param_num: 298 | print "Parameter number Error" 299 | return 300 | 301 | # check the type of parameters 302 | params_type = sorted([s for s in self._exec_flow.items() \ 303 | if int(s[0]) < 0], key=lambda x: int(x[0])) 304 | for param, p_target in zip(func_in, params_type): 305 | if type(param) == int: 306 | p_type = 0 307 | elif type(param) == list and type(param[0]) == int: 308 | p_type = 1 309 | else: 310 | p_type = -1 311 | if p_type != p_target[1][2]: 312 | print "Parameter type Error, should be %s" % \ 313 | tuple([TYPE[p[1][2]] for p in params_type]) 314 | return 315 | 316 | # execute 317 | # travel exec_flow from minimun idx 318 | progress = [p for p in func_in] # cache input of each step 319 | progress.extend([None]*len(self._steps)) 320 | exec_order = sorted(self._exec_flow.keys(), key=lambda x: int(x)) 321 | result = [] 322 | for s, i in zip(exec_order, range(len(exec_order))): 323 | next_s = self._exec_flow[s][1] 324 | if next_s is not None: 325 | next_p = int(next_s) + self._param_num 326 | if progress[next_p] is None: 327 | progress[next_p] = [0]*len(self._exec_flow[next_s][0]) 328 | idx = self._exec_flow[next_s][0].index(s) 329 | if int(s) < 0: 330 | progress[next_p][idx] = progress[i] 331 | else: 332 | step = self._steps[int(s)] 333 | ret = step.step_out(*tuple(progress[int(s)+self._param_num])) 334 | progress[next_p][idx] = ret 335 | else: 336 | step = self._steps[int(s)] 337 | result = step.step_out(*tuple(progress[int(s)+self._param_num])) 338 | 339 | return result 340 | 341 | def verify(self, samples): 342 | """ 343 | :param samples: [({'-2': param1, '-1': param2, ...}, result), ...] 344 | """ 345 | ok = 0 346 | for sample in samples: 347 | ss = sorted([p for p in sample[0].items()], \ 348 | key=lambda x: int(x[0])) 349 | ret = self.execute(tuple([s[1] for s in ss])) 350 | if ret == sample[1]: 351 | print "%s OK" % sample 352 | ok += 1 353 | else: 354 | print "Failed: %s, sample is %s, result is %s" % \ 355 | (sample[0], sample[1], ret) 356 | print "%d samples tested, ok persent is %d/%d" \ 357 | % (len(samples), ok, len(samples)) 358 | return ok, len(samples) 359 | 360 | def export(self): 361 | """ 362 | :return: (p, a, e) 363 | p --> Program (steps) 364 | a --> Attributes (attr) 365 | e --> Examples (samples) [5, 4] (input_type, input, output_type, output) 366 | """ 367 | samples = [] 368 | for s in self._samples: 369 | if len(s[0].keys()) > 1: 370 | # TODO: handle two more parameters 371 | 372 | 373 | --------------------------------------------------------------------------------