├── LICENSE ├── README.md ├── dataset ├── test.json └── train.json ├── figures ├── accuracy_per_category.png └── accuracy_per_solution_form.png └── solution ├── README.md ├── converter.py └── test.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jiwoo Kim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DMath (Diverse Math Word Problems) 2 | 3 | This repository provides DMath (**D**iverse **Math** Word Problems), a collection of 10K high-quality grade school-level math word problems for the paper "[It Ain’t Over: A Multi-aspect Diverse Math Word Problem Dataset](https://aclanthology.org/2023.emnlp-main.927.pdf)". 4 | 5 | ## Details of the dataset 6 | DMath is a multi-aspect diverse MWP dataset, which has the following key features: 7 | * It fully covers problem types across five categories. These include arithmetic calculation (ARI), comparison (COM), correspondence (COR), geometry(GEO), and possibility (POS). 8 | * It consists of about 10,000 problems manually created by 43 human workers covering various lexical usage patterns on natural language narratives and expression trees. 9 | * It supports bilingual input languages, i.e., English and Korean. 10 | * It offers the annotation of expression trees and Python code as intermediate solutions. 11 | 12 | In summary, DMath offers a wide range of diversity in problem types, lexical usage patterns, languages, and intermediate solution forms. 13 | 14 | ## Statistics of the dataset 15 | The table below shows the number of samples per category on DMath. 16 | | | ARI | COM | COR | POS | GEO | Total | 17 | |-------|------:|------:|------:|------:|------:|-------:| 18 | | Train | 2,476 | 1,338 | 1,656 | 1,417 | 1,056 | 7,943 | 19 | | Test | 669 | 334 | 402 | 383 | 291 | 2,079 | 20 | | Total | 3,145 | 1,672 | 2,058 | 1,800 | 1,347 | 10,002 | 21 | 22 | 23 | ## Data format 24 | You can see a sample of the data here. 25 | ``` 26 | "1": { 27 | "category": "Geometry", 28 | "question_ko": "테이프를 일직선으로 쭉 붙이려고 한다. 잘라낸 3개의 테이프가 각각 36센티미터(㎝), 42센티미터(㎝), 48센티미터(㎝)이고 같은 부분만큼 겹쳐서 붙이면 총 길이가 97센티미터(㎝)이다. 겹쳐진 부분의 길이는 얼마인지 구하시오.", 29 | "question_en": "We are trying to stick a tape in a straight line. The three tapes cut are 36 centimeters (cm), 42 centimeters (cm), and 48 centimeters (cm) respectively, and if the same part is overlapped and attached, the total length is 97 centimeters (cm). Find the length of the overlapping part.", 30 | "answer_ko": "14.5", 31 | "answer_en": "14.5", 32 | "solution_abst_ko": "36 42 [OP_ADD] 48 [OP_ADD] 97 [OP_SUB] 3 1 [OP_SUB] [OP_DIV]", 33 | "solution_abst_en": "36 42 [OP_ADD] 48 [OP_ADD] 97 [OP_SUB] 3 1 [OP_SUB] [OP_DIV]", 34 | "solution_code_ko": "var_a = 36\nvar_b = 42\nvar_c = var_a + var_b\nvar_d = 48\nvar_e = var_c + var_d\nvar_f = 97\nvar_g = var_e - var_f\nvar_h = 3\nvar_i = 1\nvar_j = var_h - var_i\nvar_k = var_g / var_j\nprint('{:.2f}'.format(round(var_k+1e-10,2)))", 35 | "solution_code_en": "var_a = 36\nvar_b = 42\nvar_c = var_a + var_b\nvar_d = 48\nvar_e = var_c + var_d\nvar_f = 97\nvar_g = var_e - var_f\nvar_h = 3\nvar_i = 1\nvar_j = var_h - var_i\nvar_k = var_g / var_j\nprint('{:.2f}'.format(round(var_k+1e-10,2)))" 36 | }, 37 | ``` 38 | 39 | One data consists of the following keys: 40 | * `category` : The problem types. It can be `Arithmetic Calculation`, `Comparison`, `Correspondence`, `Possibility`, and `Geometry`. 41 | * `question_ko` : The natural language narratives in Korean. 42 | * `question_en` : The natural language narratives in English. 43 | * `answer_ko` : The answer of the question in Korean. 44 | * `answer_en` : The answer of the question in English. 45 | * `solution_abst_ko` : The expression tree solution (=abstract solution) of the question in Korean. 46 | * `solution_abst_en` : The expression tree solution (=abstract solution) of the question in English. 47 | * `solution_code_ko` : The Python code solution of the question in Korean. 48 | * `solution_code_en` : The Python code solution of the question in English. 49 | 50 | ## Experimental Results 51 | The figure below shows the accuracy comparison over various reasoning categories on DMath for RoBERTa ([Liu et al., 2019](https://arxiv.org/pdf/1907.11692.pdf)), GPT-2 ([Radford et al., 2019](https://d4mucfpksywv.cloudfront.net/better-language-models/language-models.pdf)), ChatGPT (`gpt-3.5-turbo`; [OpenAI](https://platform.openai.com/docs/model-index-for-researchers)) and GPT-4 ([OpenAI, 2023](https://arxiv.org/pdf/2303.08774.pdf)). We use the fine-tuning approach for RoBERTa and GPT-2 and use the prompting approach for ChatGPT and GPT-4. The worst problem categories differ across MWP models. 52 | 53 | 54 | ![Accuracy per category](./figures/accuracy_per_category.png) 55 | 56 | The figure below shows the accuracy comparison results of MWP models on the DMath per expression forms in English. "NL prompt" means the natural language prompt. We set few-shot CoT ([Wei et al., 2022](https://arxiv.org/pdf/2201.11903.pdf)) as NL prompt and PAL ([Gao et al., 2022](https://arxiv.org/pdf/2211.10435.pdf)) as Python code prompt. We use RoBERTa ([Liu et al., 2019](https://arxiv.org/pdf/1907.11692.pdf)) and CodeGPT ([Lu et al., 2021](https://arxiv.org/pdf/2102.04664.pdf)) as the models for expression tree and Python code in the fine-tuning approach. We use GPT-4 ([OpenAI, 2023](https://arxiv.org/pdf/2303.08774.pdf)) as the models for NL prompt and Python code prompt in the prompting approach. A specific prompt type is preferred depending on the problem. 57 | 58 | 59 | ![Accuracy per solution form](./figures/accuracy_per_solution_form.png) 60 | 61 | We use `gpt-3.5-turbo-0301` for ChatGPT and `gpt-4-0314` for GPT-4. 62 | 63 | ## Citation 64 | If you find this work useful for your research, please cite our paper: 65 | ``` 66 | @inproceedings{kim-etal-2023-aint, 67 | title = "It Ain{'}t Over: A Multi-aspect Diverse Math Word Problem Dataset", 68 | author = "Kim, Jiwoo and 69 | Kim, Youngbin and 70 | Baek, Ilwoong and 71 | Bak, JinYeong and 72 | Lee, Jongwuk", 73 | editor = "Bouamor, Houda and 74 | Pino, Juan and 75 | Bali, Kalika", 76 | booktitle = "Proceedings of the 2023 Conference on Empirical Methods in Natural Language Processing", 77 | month = dec, 78 | year = "2023", 79 | address = "Singapore", 80 | publisher = "Association for Computational Linguistics", 81 | url = "https://aclanthology.org/2023.emnlp-main.927", 82 | doi = "10.18653/v1/2023.emnlp-main.927", 83 | pages = "14984--15011", 84 | abstract = "The math word problem (MWP) is a complex task that requires natural language understanding and logical reasoning to extract key knowledge from natural language narratives. Previous studies have provided various MWP datasets but lack diversity in problem types, lexical usage patterns, languages, and annotations for intermediate solutions. To address these limitations, we introduce a new MWP dataset, named DMath (Diverse Math Word Problems), offering a wide range of diversity in problem types, lexical usage patterns, languages, and intermediate solutions. The problems are available in English and Korean and include an expression tree and Python code as intermediate solutions. Through extensive experiments, we demonstrate that the DMath dataset provides a new opportunity to evaluate the capability of large language models, i.e., GPT-4 only achieves about 75{\%} accuracy on the DMath dataset.", 85 | } 86 | 87 | ``` -------------------------------------------------------------------------------- /figures/accuracy_per_category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiwooKimAR/dmath/149a7403619ac1bd6ed10f50694ad82699d5cc03/figures/accuracy_per_category.png -------------------------------------------------------------------------------- /figures/accuracy_per_solution_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiwooKimAR/dmath/149a7403619ac1bd6ed10f50694ad82699d5cc03/figures/accuracy_per_solution_form.png -------------------------------------------------------------------------------- /solution/README.md: -------------------------------------------------------------------------------- 1 | # Intermediate Solution Forms 2 | 3 | We annotate two expression formats: an expression tree and Python code. 4 | 5 | ## Definition of Operators 6 | To annotate DMath, we introduce 50 operators. Their detailed explanation can be found in Appendix B in our [paper](https://aclanthology.org/2023.emnlp-main.927.pdf). 7 | 8 | ## Python Code Conversion 9 | We implement an automatic code generator to convert the expression tree into Python code. 10 | 11 | How to use it is as follows. 12 | ``` 13 | # import `PostfixConverter` class 14 | from converter import PostfixConverter 15 | 16 | # Make an instance 17 | converter = PostfixConverter() 18 | 19 | # Target solution (expression tree solution form) 20 | solution = "12 53 1 [OP_LIST_ARANGE] 2 [OP_LIST_DIVISIBLE] [OP_SET_DIFFERENCE] [OP_LIST_MEAN]" 21 | 22 | # Get an answer and a code 23 | ans, code = converter.convert(solution) 24 | 25 | # Print 26 | print(f"Solution: {solution}\n") 27 | print(f"Answer: {ans}\n") 28 | print(f"Code:") 29 | print(code) 30 | ``` 31 | 32 | The output of the code above is as follows. 33 | ``` 34 | Solution: 12 53 1 [OP_LIST_ARANGE] 2 [OP_LIST_DIVISIBLE] [OP_SET_DIFFERENCE] [OP_LIST_MEAN] 35 | 36 | Answer: 33 37 | 38 | Code: 39 | var_a = 12 40 | var_b = 53 41 | var_c = 1 42 | list_a = [i for i in range(var_a, var_b + 1, var_c)] 43 | var_d = 2 44 | list_b = [] 45 | var_d = int(var_d) 46 | for i in list_a: 47 | i = int(i) 48 | if i % var_d == 0: 49 | list_b.append(i) 50 | list_c = list(set(list_a) - set(list_b)) 51 | list_c = [float(i) for i in list_c] 52 | var_e = sum(list_c)/len(list_c) 53 | print(int(var_e)) 54 | ``` -------------------------------------------------------------------------------- /solution/converter.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import math 3 | from string import ascii_lowercase, ascii_uppercase 4 | 5 | from functools import wraps 6 | import errno 7 | import os 8 | import signal 9 | 10 | class TimeoutError(Exception): 11 | pass 12 | 13 | def timeout(seconds=10, error_message=os.strerror(errno.ETIME)): 14 | def decorator(func): 15 | def _handle_timeout(signum, frame): 16 | raise TimeoutError(error_message) 17 | 18 | def wrapper(*args, **kwargs): 19 | signal.signal(signal.SIGALRM, _handle_timeout) 20 | signal.alarm(seconds) 21 | try: 22 | result = func(*args, **kwargs) 23 | finally: 24 | signal.alarm(0) 25 | return result 26 | 27 | return wraps(func)(wrapper) 28 | 29 | return decorator 30 | 31 | class StacknNames: # class comprises 2 stacks 32 | def __init__(self): 33 | self.content_stack = [] # stack for saving values 34 | self.name_stack = [] # stack for saving the vairable names 35 | def pop(self): 36 | if len(self.content_stack) < 1: 37 | return None 38 | return self.content_stack.pop(), self.name_stack.pop() 39 | 40 | def push(self, item, new_name): 41 | self.content_stack.append(item) 42 | self.name_stack.append(new_name) # New item is always saved with new variable names 43 | 44 | def size(self): 45 | return len(self.content_stack) 46 | 47 | 48 | class PostfixConverter(): 49 | def __init__(self): 50 | # operator_dic = {operator:['what it does', '# of input', 'type of operator', '# of operand created', '# of lists created']} 51 | self.operator_dic = { 52 | '[OP_ADD]':['+', 2, 'infix', 1, 0], 53 | '[OP_SUB]':['-', 2, 'infix', 1, 0], 54 | '[OP_DIV]':['/', 2, 'infix', 1, 0], 55 | '[OP_MUL]':['*', 2, 'infix', 1, 0], 56 | '[OP_FDIV]':['//', 2, 'infix', 1, 0], 57 | '[OP_MOD]':['%', 2, 'infix', 1, 0], 58 | '[OP_POW]':['**', 2, 'infix', 1, 0], 59 | '[OP_CEIL]':['int', 2, 'function', 1, 0], 60 | '[OP_FLOOR]':['int', 2, 'function', 1, 0], 61 | '[OP_ROUND]':['round', 2, 'function', 1, 0], 62 | '[OP_ABS]':['abs', 1, 'function', 1, 0], 63 | '[OP_COMB]':['math.comb', 2, 'function', 1, 0], 64 | '[OP_PERM]':['math.perm', 2, 'function', 1, 0], 65 | '[OP_GCD]': ['math.gcd', 2, 'function'], 66 | '[OP_LCM]': ['', 2, 'function'], 67 | '[OP_LIST_SOL]':['',0,'list', 1, 0], 68 | '[OP_LIST_EOL]':['',0,'list', 99, 1], 69 | '[OP_LIST_ARANGE]':['', 3, 'list_function'], 70 | '[OP_LIST_ODD]':['', 2, 'list_function'], 71 | '[OP_LIST_EVEN]':['', 2, 'list_function'], 72 | '[OP_LIST_POP]':['',0,'list', 0 , -1], 73 | '[OP_LIST_GET_PERM]':['', 2, 'list_function'], 74 | '[OP_LIST_GET_PRODUCT]':['', 2, 'list_function'], 75 | '[OP_GEN_POSSIBLE_LIST]':['',1,'function_special'], 76 | '[OP_LIST_MAX]':['max',2,'list_function'], 77 | '[OP_LIST_MIN]':['min',2,'list_function'], 78 | '[OP_LIST_SUM]':['sum',1,'list_function'], 79 | '[OP_LIST_LEN]':['len',1,'list_function'], 80 | '[OP_LIST_GET]':['', 2, 'list_function'], 81 | '[OP_LIST_INDEX]':['', 2, 'list_function'], 82 | '[OP_LIST_FIND_NUM]':['',2,'list_function'], 83 | '[OP_LIST_MORE]':['', 2, 'list_function'], 84 | '[OP_LIST_LESS]':['', 2, 'list_function'], 85 | '[OP_LIST_MORE_EQUAL]':['', 2, 'list_function'], 86 | '[OP_LIST_LESS_EQUAL]':['', 2, 'list_function'], 87 | '[OP_SET_UNION]':['', 2, 'list_function'], 88 | '[OP_SET_DIFFERENCE]':['', 2, 'list_function'], 89 | '[OP_SET_INTERSECT]':['', 2, 'list_function'], 90 | '[OP_LIST_DIVISIBLE]':['',2,'list_function'], 91 | '[OP_LIST_DIVIDE_AND_REMAIN]':['',3,'list_function',0,1], 92 | '[OP_LIST_GET_DIVISOR]': ['', 1, 'list_function'], 93 | '[OP_LIST_COND_MAX_MIN]':['comp',2,'list_function'], 94 | '[OP_LIST2NUM]':['',1,'list_function'], 95 | '[OP_NUM2LIST]':['', 1, 'list_function'], 96 | '[OP_LIST_NUM2SUM]':['',1,'list_function',0,1], 97 | '[OP_LIST_SEARCH_FIXED_DIGIT]':['',3,'list_function',0,1], 98 | '[OP_DIGIT_UNK_SOLVER]':['',2,'function_special',1, 0], 99 | '[OP_LIST_FIND_UNK]':['',3,'list_function'], 100 | '[OP_NUM_UNK_SOLVER]':['',2,'function_special',1, 0], 101 | '[OP_LIST_MEAN]':['average',1,'list_function'], 102 | } 103 | 104 | self.operand_names = ['var_'+c for c in ascii_lowercase] + ['var_'+c for c in ascii_uppercase] + ['var_'+c for c in '0123456789'] 105 | for c in ascii_lowercase: 106 | for d in ascii_lowercase: 107 | self.operand_names.append(f'var_{c}{d}') 108 | self.list_names = ['list_'+c for c in ascii_lowercase] 109 | 110 | self.operand_stack = StacknNames() 111 | self.list_stack = StacknNames() 112 | self.code_string = '' 113 | 114 | # convert number to int type if possible, or make it as float type 115 | self.intifint = lambda x: int(x) if int(x) == self.to_float(x) else self.to_float(x) 116 | 117 | def to_float(self, frac_str): # Process the fractional input string 118 | try: 119 | return float(frac_str) 120 | except ValueError: 121 | num, denom = frac_str.split('/') 122 | try: 123 | leading, num = num.split(' ') 124 | whole = float(leading) 125 | except ValueError: 126 | whole = 0 127 | frac = float(num) / float(denom) 128 | return whole - frac if whole < 0 else whole + frac 129 | 130 | 131 | def is_number(self, value): 132 | try: 133 | self.to_float(value) 134 | return True 135 | except ValueError: 136 | return False 137 | 138 | def is_fraction(self, value): 139 | try: 140 | float(value) 141 | return False 142 | except: 143 | return True 144 | 145 | # convert function 146 | @timeout(10) 147 | def convert(self, postfix_eq): 148 | # Core function: Generate code given postfix equation 149 | self.__init__() 150 | operand_operator_list = postfix_eq.split() 151 | for n, i in enumerate(operand_operator_list): 152 | if i in self.operator_dic: # if operator 153 | operator_name = i 154 | operator_info = self.operator_dic[i] 155 | 156 | # list exceptional functions - init 157 | if operator_info[2] == 'list': 158 | if i == '[OP_LIST_SOL]': 159 | self.operand_stack.push('SOL', 'SOL') 160 | elif i == '[OP_LIST_EOL]': 161 | new_list = [] 162 | list_name = self.list_names.pop(0) 163 | self.code_string += '{}= []\n'.format(list_name) 164 | while True: 165 | element, var_name = self.operand_stack.pop() 166 | if element == 'SOL': 167 | new_list.reverse() 168 | self.code_string += '{}.reverse()\n'.format(list_name) 169 | self.list_stack.push(new_list, list_name) # Keep the stack of lists seperate 170 | break 171 | if '/' in str(element): 172 | element = eval(str(element)) 173 | new_list.append(element) 174 | self.code_string += 'if "/" in str({var_name}):\n {var_name} = eval(str({var_name}))\n{list_name}.append({var_name})\n'.format(list_name=list_name, var_name=var_name) 175 | 176 | elif i == '[OP_LIST_POP]': 177 | self.list_stack.pop() 178 | else: 179 | print("not defined") 180 | 181 | # Operators in infix form: + - * / // % ** 182 | elif operator_info[2] == 'infix': 183 | b, b_name = self.operand_stack.pop() 184 | a, a_name = self.operand_stack.pop() 185 | 186 | var_name = self.operand_names.pop(0) 187 | self.code_string += '{var} = {a} {operator} {b}\n'.format(var = var_name, a=a_name, operator=operator_info[0], b=b_name) 188 | intermediate_eq = "{}".format(str(a) + operator_info[0] +str(b)) 189 | intermediate = eval(intermediate_eq) 190 | self.operand_stack.push(intermediate, var_name) 191 | 192 | # function: math.perm(num1, num2) etc. 193 | elif operator_info[2] == 'function': 194 | var_name = self.operand_names.pop(0) 195 | if operator_info[1]==1: 196 | a, a_name = self.operand_stack.pop() 197 | intermediate_eq = str(operator_info[0]+'('+str(a)+')') 198 | intermediate = eval(intermediate_eq) 199 | self.code_string += '{} = {}({})\n'.format(var_name, operator_info[0], a_name) 200 | 201 | elif operator_info[1]==2: 202 | if operator_name == '[OP_GCD]': 203 | num1, num1_name = self.operand_stack.pop() 204 | num2, num2_name = self.operand_stack.pop() 205 | num1, num2 = int(num1), int(num2) 206 | 207 | intermediate = math.gcd(num1, num2) 208 | self.code_string += '{new_var} = math.gcd(int({var1}), int({var2}))\n'.format(new_var=var_name, var1=num1_name, var2=num2_name) 209 | 210 | elif operator_name == '[OP_LCM]': 211 | num1, num1_name = self.operand_stack.pop() 212 | num2, num2_name = self.operand_stack.pop() 213 | num1, num2 = int(num1), int(num2) 214 | 215 | intermediate = num1 * num2 / math.gcd(num1, num2) 216 | self.code_string += '{new_var} = {var1} * {var2} / math.gcd(int({var1}), int({var2}))\n'.format(new_var=var_name, var1=num1_name, var2=num2_name) 217 | 218 | elif operator_name in ['[OP_CEIL]', '[OP_FLOOR]']: 219 | b, b_name = self.operand_stack.pop() 220 | b = int(b) 221 | a, a_name = self.operand_stack.pop() 222 | if operator_name == '[OP_CEIL]': 223 | try: 224 | # rounding intergers 225 | int(a) 226 | intermediate_eq = 'int((({a}+9*10**({b}-2))//(10**({b}-1)))*10**({b}-1))\n'.format(a=a_name, b=b_name) 227 | intermediate = eval('int((({a}+9*10**({b}-2))//(10**({b}-1)))*10**({b}-1))\n'.format(a=a, b=b)) 228 | self.code_string += '{var}={eq}\n'.format(var=var_name, eq=intermediate_eq) 229 | except: 230 | # int(float) -> floor / int(float+1) -> ceil 231 | intermediate_eq = 'int({a}*10**{b}+1)/10**{b}\n'.format(a=a_name, b=b_name) 232 | intermediate = eval('int({a}*10**{b}+1)/10**{b}\n'.format(a=a, b=b)) 233 | self.code_string += '{var}={eq}\n'.format(var=var_name, eq=intermediate_eq) 234 | else: # [OP_FLOOR] 235 | try: 236 | int(a) 237 | intermediate_eq = 'int(({a}//(10**({b}-1)))*10**({b}-1))\n'.format(a=a_name, b=b_name) 238 | intermediate = eval('int(({a}//(10**({b}-1)))*10**({b}-1))\n'.format(a=a, b=b)) 239 | self.code_string += '{var}={eq}\n'.format(var=var_name, eq=intermediate_eq) 240 | except: 241 | intermediate_eq = 'int({a}*10**{b})/10**{b}\n'.format(a=a_name, b=b_name) 242 | intermediate = eval('int({a}*10**{b})/10**{b}\n'.format(a=a, b=b)) 243 | self.code_string += '{var}={eq}\n'.format(var=var_name, eq=intermediate_eq) 244 | elif operator_name == '[OP_ROUND]': 245 | b, b_name = self.operand_stack.pop() 246 | b = int(b) 247 | a, a_name = self.operand_stack.pop() 248 | try: 249 | int(str(a)) 250 | round_tgt = int(a//10**(b-2))%10 251 | if round_tgt >= 5: 252 | intermediate = int(((a+9*10**(b-2))//(10**(b-1)))*10**(b-1)) 253 | else: 254 | intermediate = int((a//(10**(b-1)))*10**(b-1)) 255 | self.code_string += "round_tgt = int({a}//10**({b}-2)%10)\n\ 256 | if round_tgt >= 5:\n\ 257 | {intermediate} = int((({a}+9*10**({b}-2))//(10**({b}-1)))*10**({b}-1))\n\ 258 | else:\n\ 259 | {intermediate} = int(({a}//(10**({b}-1)))*10**({b}-1))".format(a=a, b=b, intermediate=var_name) 260 | except: 261 | a = self.to_float(a) 262 | intermediate = round(a+1e-10, b) # Add epsilon to get the correct value. 1.7325 -> round(1.7325, 3) -> 1.732 / round(1.7325000001, 3) -> 1.733 263 | self.code_string += '{var} = round(float({a})+1e-10, {b})\n'.format(var=var_name, a=a_name, b=b_name) 264 | 265 | elif operator_name == '[OP_COMB]': 266 | b, b_name = self.operand_stack.pop() 267 | a, a_name = self.operand_stack.pop() 268 | intermediate = 1 269 | a = int(a) 270 | b = int(b) 271 | for i, elem in enumerate(range(b)): 272 | intermediate = intermediate * (a-i) 273 | for i, elem in enumerate(range(b)): 274 | intermediate = intermediate / (i+1) 275 | self.code_string += '{new_var} = 1\n\ 276 | {a} = int({a})\n\ 277 | {b} = int({b})\n\ 278 | for i, elem in enumerate(range({b})):\n\ 279 | {new_var} = {new_var} * ({a}-i)\n\ 280 | for i, elem in enumerate(range({b})):\n\ 281 | {new_var} = {new_var} / (i+1)\n'.format(new_var=var_name, a=a_name, b=b_name) 282 | elif operator_name == '[OP_PERM]': 283 | b, b_name = self.operand_stack.pop() 284 | a, a_name = self.operand_stack.pop() 285 | intermediate = 1 286 | a = int(a) 287 | b = int(b) 288 | for i, elem in enumerate(range(b)): 289 | intermediate = intermediate * (a-i) 290 | self.code_string += '{new_var} = 1\n\ 291 | {a} = int({a})\n\ 292 | {b} = int({b})\n\ 293 | for i, elem in enumerate(range({b})):\n\ 294 | {new_var} = {new_var} * ({a}-i)\n'.format(new_var=var_name, a=a_name, b=b_name) 295 | else: # currently unused parts. Available above Python 3.8 version. 296 | b, b_name = self.operand_stack.pop() 297 | a, a_name = self.operand_stack.pop() 298 | intermediate_eq = str(operator_info[0])+'('+a_name+','+b_name+')' 299 | intermediate = eval(intermediate_eq) 300 | self.code_string += '{var} = {intermediate}\n'.format(var=var_name, intermediate=intermediate_eq) 301 | else: 302 | print("not defined") 303 | self.operand_stack.push(intermediate, var_name) 304 | elif operator_info[2] == 'function_special': 305 | if operator_name == '[OP_DIGIT_UNK_SOLVER]': 306 | x, x_name = self.operand_stack.pop() 307 | eq, eq_name = self.operand_stack.pop() 308 | eq = str(eq) 309 | eq = eq.replace('×','*') 310 | eq = eq.replace('x','*') 311 | eq = eq.replace('÷','/') 312 | ans_dict = dict() 313 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']) 314 | ans_dict = {v:[] for v in set(eq) & variable_candi} 315 | candi = list(itertools.product('0123456789', repeat=len(ans_dict))) 316 | for c in candi: 317 | temp = eq 318 | for i, (k, _) in enumerate(ans_dict.items()): 319 | temp = temp.replace(k, str(c[i])) 320 | term_list = [] 321 | op_list = [] 322 | temp_c = '' 323 | for tc in temp: 324 | if tc not in '+-*/=><().': 325 | temp_c += tc 326 | else: 327 | op_list.append(tc) 328 | term_list.append(temp_c) 329 | temp_c = '' 330 | term_list.append(temp_c) 331 | new_eq = '' 332 | for i in range(len(op_list)): 333 | new_eq += str(int(term_list[i]))+op_list[i] 334 | new_eq += str(int(term_list[-1])) 335 | if len(new_eq) == len(eq): 336 | new_eq=new_eq.replace('=', '==') 337 | new_eq=new_eq.replace('>==', '>=') 338 | new_eq=new_eq.replace('<==', '<=') 339 | eval_result = False 340 | try: 341 | eval_result = eval(new_eq) 342 | except: 343 | pass 344 | if eval_result: 345 | for i, (k, _) in enumerate(ans_dict.items()): 346 | ans_dict[k].append(int(c[i])) 347 | 348 | intermediate = list(set(ans_dict[x])) 349 | if len(intermediate) == 1: 350 | intermediate = intermediate[0] 351 | 352 | if isinstance(intermediate, list): 353 | new_list_name = self.list_names.pop(0) 354 | self.list_stack.push(intermediate, new_list_name) 355 | self.code_string += "ans_dict = dict()\n\ 356 | {eq} = {eq}.replace('×','*')\n\ 357 | {eq} = {eq}.replace('x','*')\n\ 358 | {eq} = {eq}.replace('÷','/')\n\ 359 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])\n\ 360 | for v in set({eq}):\n\ 361 | if v in variable_candi:\n\ 362 | ans_dict[v] = []\n\ 363 | candi = list(itertools.product('0123456789', repeat=len(ans_dict)))\n\ 364 | for c in candi:\n\ 365 | temp = {eq}\n\ 366 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 367 | temp = temp.replace(k, str(c[i]))\n\ 368 | term_list = []\n\ 369 | op_list = []\n\ 370 | temp_c = ''\n\ 371 | for tc in temp:\n\ 372 | if tc not in '+-*/=><().':\n\ 373 | temp_c += tc\n\ 374 | else:\n\ 375 | op_list.append(tc)\n\ 376 | term_list.append(temp_c)\n\ 377 | temp_c = ''\n\ 378 | term_list.append(temp_c)\n\ 379 | new_eq = ''\n\ 380 | for i in range(len(op_list)):\n\ 381 | new_eq += str(int(term_list[i]))+op_list[i]\n\ 382 | new_eq += str(int(term_list[-1]))\n\ 383 | if len(new_eq) == len({eq}):\n\ 384 | new_eq=new_eq.replace('=', '==')\n\ 385 | new_eq=new_eq.replace('>==', '>=')\n\ 386 | new_eq=new_eq.replace('<==', '<=')\n\ 387 | eval_result = False\n\ 388 | try:\n\ 389 | eval_result = eval(new_eq)\n\ 390 | except:\n\ 391 | pass\n\ 392 | if eval_result:\n\ 393 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 394 | ans_dict[k].append(int(c[i]))\n\ 395 | {intermediate} = list(set(ans_dict[{x}]))\n".format(intermediate=new_list_name, eq=eq_name, x=x_name) 396 | else: 397 | new_var_name = self.operand_names.pop(0) 398 | self.operand_stack.push(intermediate, new_var_name) 399 | self.code_string += "ans_dict = dict()\n\ 400 | {eq} = {eq}.replace('×','*')\n\ 401 | {eq} = {eq}.replace('x','*')\n\ 402 | {eq} = {eq}.replace('÷','/')\n\ 403 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])\n\ 404 | for v in set({eq}):\n\ 405 | if v in variable_candi:\n\ 406 | ans_dict[v] = 1\n\ 407 | candi = list(itertools.product('0123456789', repeat=len(ans_dict)))\n\ 408 | for c in candi:\n\ 409 | temp = {eq}\n\ 410 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 411 | temp = temp.replace(k, str(c[i]))\n\ 412 | term_list = []\n\ 413 | op_list = []\n\ 414 | temp_c = ''\n\ 415 | for tc in temp:\n\ 416 | if tc not in '+-*/=><().':\n\ 417 | temp_c += tc\n\ 418 | else:\n\ 419 | op_list.append(tc)\n\ 420 | term_list.append(temp_c)\n\ 421 | temp_c = ''\n\ 422 | term_list.append(temp_c)\n\ 423 | new_eq = ''\n\ 424 | for i in range(len(op_list)):\n\ 425 | new_eq += str(int(term_list[i]))+op_list[i]\n\ 426 | new_eq += str(int(term_list[-1]))\n\ 427 | if len(new_eq) == len({eq}):\n\ 428 | new_eq=new_eq.replace('=', '==')\n\ 429 | new_eq=new_eq.replace('>==', '>=')\n\ 430 | new_eq=new_eq.replace('<==', '<=')\n\ 431 | eval_result = False\n\ 432 | try:\n\ 433 | eval_result = eval(new_eq)\n\ 434 | except:\n\ 435 | pass\n\ 436 | if eval_result:\n\ 437 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 438 | ans_dict[k] = int(c[i])\n\ 439 | {intermediate} = ans_dict[{x}]\n".format(intermediate=new_var_name, eq=eq_name, x=x_name) 440 | elif operator_name == '[OP_NUM_UNK_SOLVER]': 441 | x, x_name = self.operand_stack.pop() 442 | eq, eq_name = self.operand_stack.pop() 443 | eq = str(eq) 444 | eq = eq.replace('×','*') 445 | eq = eq.replace('x','*') 446 | eq = eq.replace('÷','/') 447 | ans_dict = dict() 448 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']) 449 | ans_dict = {v:[] for v in set(eq) & variable_candi} 450 | candidate_num = [i for i in range(51)] 451 | candi = list(itertools.product(candidate_num, repeat=len(ans_dict))) 452 | for c in candi: 453 | temp = eq 454 | for i, (k, _) in enumerate(ans_dict.items()): 455 | temp = temp.replace(k, str(c[i])) 456 | term_list = [] 457 | op_list = [] 458 | temp_c = '' 459 | for tc in temp: 460 | if tc not in '+-*/=><().': 461 | temp_c += tc 462 | else: 463 | op_list.append(tc) 464 | term_list.append(temp_c) 465 | temp_c = '' 466 | term_list.append(temp_c) 467 | new_eq = '' 468 | for i in range(len(op_list)): 469 | if term_list[i] == '': 470 | new_eq += str(term_list[i])+op_list[i] 471 | else: 472 | new_eq += str(int(term_list[i]))+op_list[i] 473 | new_eq += str(int(term_list[-1])) 474 | new_eq=new_eq.replace('=', '==') 475 | new_eq=new_eq.replace('>==', '>=') 476 | new_eq=new_eq.replace('<==', '<=') 477 | eval_result = False 478 | try: 479 | if '=' in new_eq and '>' not in new_eq and '<' not in new_eq: 480 | new_eq=new_eq.replace('==','=') 481 | new_eq=new_eq.replace('>','') 482 | new_eq=new_eq.replace('<','') 483 | new_eq=new_eq.split('=') 484 | for i in range(len(new_eq)-1): 485 | eval_result = math.isclose(eval(new_eq[i]), eval(new_eq[i+1])) 486 | if not eval_result: 487 | break 488 | else: 489 | eval_result = eval(new_eq) 490 | except: 491 | eval_result = False 492 | pass 493 | if eval_result: 494 | for i, (k, _) in enumerate(ans_dict.items()): 495 | ans_dict[k].append(int(c[i])) 496 | 497 | intermediate = list(set(ans_dict[x])) 498 | if len(intermediate) == 1: 499 | intermediate = intermediate[0] 500 | 501 | if isinstance(intermediate, list): 502 | new_list_name = self.list_names.pop(0) 503 | self.list_stack.push(intermediate, new_list_name) 504 | self.code_string += "ans_dict = dict()\n\ 505 | {eq} = {eq}.replace('×','*')\n\ 506 | {eq} = {eq}.replace('x','*')\n\ 507 | {eq} = {eq}.replace('÷','/')\n\ 508 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])\n\ 509 | for v in set({eq}):\n\ 510 | if v in variable_candi:\n\ 511 | ans_dict[v] = []\n\ 512 | candidate_num = [i for i in range(51)]\n\ 513 | candi = list(itertools.product(candidate_num, repeat=len(ans_dict)))\n\ 514 | for c in candi:\n\ 515 | temp = {eq}\n\ 516 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 517 | temp = temp.replace(k, str(c[i]))\n\ 518 | term_list = []\n\ 519 | op_list = []\n\ 520 | temp_c = ''\n\ 521 | for tc in temp:\n\ 522 | if tc not in '+-*/=><().':\n\ 523 | temp_c += tc\n\ 524 | else:\n\ 525 | op_list.append(tc)\n\ 526 | term_list.append(temp_c)\n\ 527 | temp_c = ''\n\ 528 | term_list.append(temp_c)\n\ 529 | new_eq = ''\n\ 530 | for i in range(len(op_list)):\n\ 531 | if term_list[i] == '':\n\ 532 | new_eq += str(term_list[i])+op_list[i]\n\ 533 | else:\n\ 534 | new_eq += str(int(term_list[i]))+op_list[i]\n\ 535 | new_eq += str(int(term_list[-1]))\n\ 536 | new_eq=new_eq.replace('=', '==')\n\ 537 | new_eq=new_eq.replace('>==', '>=')\n\ 538 | new_eq=new_eq.replace('<==', '<=')\n\ 539 | eval_result = False\n\ 540 | try:\n\ 541 | if '=' in new_eq and '>' not in new_eq and '<' not in new_eq:\n\ 542 | new_eq=new_eq.replace('==','=')\n\ 543 | new_eq=new_eq.replace('>','')\n\ 544 | new_eq=new_eq.replace('<','')\n\ 545 | new_eq=new_eq.split('=')\n\ 546 | for i in range(len(new_eq)-1):\n\ 547 | eval_result = math.isclose(eval(new_eq[i]), eval(new_eq[i+1]))\n\ 548 | if not eval_result:\n\ 549 | break\n\ 550 | else:\n\ 551 | eval_result = eval(new_eq)\n\ 552 | except:\n\ 553 | eval_result = False\n\ 554 | pass\n\ 555 | if eval_result:\n\ 556 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 557 | ans_dict[k].append(int(c[i]))\n\ 558 | {intermediate} = list(set(ans_dict[{x}]))\n".format(intermediate=new_list_name, eq=eq_name, x=x_name) 559 | else: 560 | new_var_name = self.operand_names.pop(0) 561 | self.operand_stack.push(intermediate, new_var_name) 562 | self.code_string += "ans_dict = dict()\n\ 563 | {eq} = {eq}.replace('×','*')\n\ 564 | {eq} = {eq}.replace('x','*')\n\ 565 | {eq} = {eq}.replace('÷','/')\n\ 566 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])\n\ 567 | for v in set({eq}):\n\ 568 | if v in variable_candi:\n\ 569 | ans_dict[v] = 0\n\ 570 | candidate_num = [i for i in range(51)]\n\ 571 | candi = list(itertools.product(candidate_num, repeat=len(ans_dict)))\n\ 572 | for c in candi:\n\ 573 | temp = {eq}\n\ 574 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 575 | temp = temp.replace(k, str(c[i]))\n\ 576 | term_list = []\n\ 577 | op_list = []\n\ 578 | temp_c = ''\n\ 579 | for tc in temp:\n\ 580 | if tc not in '+-*/=><().':\n\ 581 | temp_c += tc\n\ 582 | else:\n\ 583 | op_list.append(tc)\n\ 584 | term_list.append(temp_c)\n\ 585 | temp_c = ''\n\ 586 | term_list.append(temp_c)\n\ 587 | new_eq = ''\n\ 588 | for i in range(len(op_list)):\n\ 589 | if term_list[i] == '':\n\ 590 | new_eq += str(term_list[i])+op_list[i]\n\ 591 | else:\n\ 592 | new_eq += str(int(term_list[i]))+op_list[i]\n\ 593 | new_eq += str(int(term_list[-1]))\n\ 594 | new_eq=new_eq.replace('=', '==')\n\ 595 | new_eq=new_eq.replace('>==', '>=')\n\ 596 | new_eq=new_eq.replace('<==', '<=')\n\ 597 | eval_result = False\n\ 598 | try:\n\ 599 | if '=' in new_eq and '>' not in new_eq and '<' not in new_eq:\n\ 600 | new_eq=new_eq.replace('==','=')\n\ 601 | new_eq=new_eq.replace('>','')\n\ 602 | new_eq=new_eq.replace('<','')\n\ 603 | new_eq=new_eq.split('=')\n\ 604 | for i in range(len(new_eq)-1):\n\ 605 | eval_result = math.isclose(eval(new_eq[i]), eval(new_eq[i+1]))\n\ 606 | if not eval_result:\n\ 607 | break\n\ 608 | else:\n\ 609 | eval_result = eval(new_eq)\n\ 610 | except:\n\ 611 | eval_result = False\n\ 612 | pass\n\ 613 | if eval_result:\n\ 614 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 615 | ans_dict[k] = int(c[i])\n\ 616 | {intermediate} = ans_dict[{x}]\n".format(intermediate=new_var_name, eq=eq_name, x=x_name) 617 | elif operator_name == '[OP_GEN_POSSIBLE_LIST]': 618 | unk, unk_name = self.operand_stack.pop() 619 | unk = str(unk) 620 | ans_dict = dict() 621 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']) 622 | ans_dict = {v:0 for v in set(unk) & variable_candi} 623 | candi = list(itertools.product('0123456789', repeat=len(ans_dict))) 624 | intermediate_list = [] 625 | for c in candi: 626 | temp = unk 627 | for i, (k, _) in enumerate(ans_dict.items()): 628 | temp = temp.replace(k, str(c[i])) 629 | if len(unk) == len(str(int(temp))): 630 | new_elem = int(temp) 631 | intermediate_list.append(new_elem) 632 | 633 | new_list_name = self.list_names.pop(0) 634 | self.operand_stack.push(unk, unk_name) 635 | self.list_stack.push(intermediate_list, new_list_name) 636 | self.code_string += "ans_dict = dict()\n\ 637 | {unk} = str({unk})\n\ 638 | {intermediate_list} = []\n\ 639 | variable_candi = set(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])\n\ 640 | for v in set({unk}):\n\ 641 | if v in variable_candi:\n\ 642 | ans_dict[v] = 0\n\ 643 | candi = list(itertools.product('0123456789', repeat=len(ans_dict)))\n\ 644 | for c in candi:\n\ 645 | temp = {unk}\n\ 646 | for i, (k, _) in enumerate(ans_dict.items()):\n\ 647 | temp = temp.replace(k, str(c[i]))\n\ 648 | if len({unk}) == len(str(int(temp))):\n\ 649 | new_elem = int(temp)\n\ 650 | {intermediate_list}.append(new_elem)\n".format(unk=unk_name, intermediate_list=new_list_name) 651 | 652 | elif operator_info[2] == 'list_function': 653 | if operator_info[1]==1: # input: list / output: scalar 654 | if operator_name == '[OP_LIST_MEAN]': 655 | temp_list, temp_lname = self.list_stack.pop() 656 | temp_list = [self.to_float(i) for i in temp_list] 657 | intermediate = sum(temp_list) / len(temp_list) 658 | new_var_name = self.operand_names.pop(0) 659 | self.code_string += '{temp_list} = [float(i) for i in {temp_list}]\n\ 660 | {new_var_name} = sum({temp_list})/len({temp_list})\n'.format(new_var_name=new_var_name, temp_list=temp_lname) 661 | self.operand_stack.push(intermediate, new_var_name) 662 | self.list_stack.push(temp_list, temp_lname) 663 | elif operator_name == '[OP_LIST_SUM]': 664 | temp_list, temp_lname = self.list_stack.pop() 665 | temp_list = [self.to_float(i) for i in temp_list] 666 | intermediate = sum(temp_list) 667 | new_var_name = self.operand_names.pop(0) 668 | self.code_string += '{temp_list} = [float(i) for i in {temp_list}]\n\ 669 | {new_var_name} = sum({temp_list})\n'.format(new_var_name=new_var_name, temp_list=temp_lname) 670 | self.operand_stack.push(intermediate, new_var_name) 671 | self.list_stack.push(temp_list, temp_lname) 672 | elif operator_name == '[OP_LIST2NUM]': 673 | temp_list, temp_lname = self.list_stack.pop() 674 | new_var_name = self.operand_names.pop(0) 675 | intermediate = '' 676 | for i in temp_list: 677 | i = str(i) 678 | intermediate = intermediate + i 679 | self.code_string += '{new_var_name}=""\n\ 680 | for i in {temp_list}:\n\ 681 | i = str(i)\n\ 682 | {new_var_name} = {new_var_name} + i\n'.format(new_var_name = new_var_name, temp_list = temp_lname) 683 | self.operand_stack.push(intermediate, new_var_name) 684 | self.list_stack.push(temp_list,temp_lname) 685 | elif operator_name == '[OP_NUM2LIST]': 686 | a, a_name = self.operand_stack.pop() 687 | new_list_name = self.list_names.pop(0) 688 | intermediate_list = [] 689 | a = int(a) 690 | while a//10 > 0: 691 | intermediate_list.append(a%10) 692 | a = a//10 693 | intermediate_list.append(a%10) 694 | intermediate_list = intermediate_list[::-1] 695 | self.code_string += '{new_list_name} = []\n\ 696 | {a} = int({a})\n\ 697 | while {a}//10 > 0:\n\ 698 | {new_list_name}.append({a}%10)\n\ 699 | {a} = {a}//10\n\ 700 | {new_list_name}.append({a}%10)\n\ 701 | {new_list_name} = {new_list_name}[::-1]\n'.format(a=a_name, new_list_name=new_list_name) 702 | self.list_stack.push(intermediate_list, new_list_name) 703 | elif operator_name == '[OP_LIST_NUM2SUM]': 704 | temp_list, temp_lname = self.list_stack.pop() 705 | a_name = self.operand_names.pop(0) 706 | new_list_name = self.list_names.pop(0) 707 | intermediate_list = [] 708 | for i in temp_list: 709 | element = 0 710 | i = int(i) 711 | while i//10 > 0: 712 | element = element + i%10 713 | i = i//10 714 | element = element + i%10 715 | intermediate_list.append(element) 716 | self.code_string += "{intermediate_list}=[]\n\ 717 | for i in {temp_list}:\n\ 718 | {a_name} = 0\n\ 719 | i = int(i)\n\ 720 | while i//10 > 0:\n\ 721 | {a_name} = {a_name} + i%10\n\ 722 | i = i//10\n\ 723 | {a_name} = {a_name} + i%10\n\ 724 | {intermediate_list}.append({a_name})\n".format(intermediate_list=new_list_name, temp_list=temp_lname, a_name=a_name) 725 | self.list_stack.push(intermediate_list, new_list_name) 726 | elif operator_name == '[OP_LIST_GET_DIVISOR]': 727 | num, num_name = self.operand_stack.pop() 728 | new_list_name = self.list_names.pop(0) 729 | num = int(num) 730 | intermediate_list = [] 731 | num_sqrt = int(math.sqrt(num)) 732 | for i in range(1, num_sqrt+1): 733 | if num % i == 0: 734 | intermediate_list.append(i) 735 | intermediate_list.append(int(num/i)) 736 | new_list = sorted(set(intermediate_list)) 737 | self.list_stack.push(new_list, new_list_name) 738 | self.code_string += "{intermediate_list} = []\n\ 739 | num_sqrt = int(math.sqrt({num_name}))\n\ 740 | for i in range(1, num_sqrt+1):\n\ 741 | if {num_name} % i == 0:\n\ 742 | {intermediate_list}.append(i)\n\ 743 | {intermediate_list}.append(int({num_name}/i))\n\ 744 | {intermediate_list} = sorted(set({intermediate_list}))\n".format(num_name=num_name, intermediate_list=new_list_name) 745 | else: # [OP_LIST_LEN] 746 | temp_list, temp_lname = self.list_stack.pop() 747 | intermediate_eq = operator_info[0]+'('+str(temp_list)+')' 748 | intermediate = eval(intermediate_eq) 749 | new_var_name = self.operand_names.pop(0) 750 | self.code_string += '{} = {}({})\n'.format(new_var_name, operator_info[0], temp_lname) 751 | self.operand_stack.push(intermediate, new_var_name) 752 | self.list_stack.push(temp_list, temp_lname) 753 | elif operator_info[1]==2: 754 | if operator_name in ['[OP_LIST_MAX]', '[OP_LIST_MIN]', '[OP_LIST_GET]', '[OP_LIST_INDEX]', '[OP_LIST_MORE]', '[OP_LIST_LESS]', '[OP_LIST_MORE_EQUAL]', '[OP_LIST_LESS_EQUAL]', \ 755 | '[OP_LIST_GET_PERM]', '[OP_LIST_GET_PRODUCT]']:# input: list, scalar / output: scalar, list 756 | temp_list, temp_lname = self.list_stack.pop() 757 | a, a_name = self.operand_stack.pop() 758 | try: 759 | a = self.to_float(a) 760 | a = self.intifint(a) 761 | except: 762 | pass 763 | if operator_name == '[OP_LIST_GET]': # input: list, scalar / output: scalar 764 | # print('[OP_LIST_GET]', temp_list) 765 | intermediate = temp_list[a-1] 766 | new_var_name = self.operand_names.pop(0) 767 | self.code_string += '{} = {}[{}-1]\n'.format(new_var_name, temp_lname, a_name) 768 | self.list_stack.push(temp_list, temp_lname) 769 | self.operand_stack.push(intermediate, new_var_name) 770 | elif operator_name == '[OP_LIST_INDEX]': # input: list, scalar / output: scalar 771 | if isinstance(a, int): 772 | try: 773 | try: 774 | intermediate = temp_list.index(str(a))+1 775 | except: 776 | intermediate = temp_list.index(str(float(a)))+1 777 | except: 778 | try: 779 | intermediate = temp_list.index(int(a))+1 780 | except: 781 | intermediate = temp_list.index(float(a))+1 782 | 783 | elif isinstance(a, float): 784 | try: 785 | intermediate = temp_list.index(str(a))+1 786 | except: 787 | intermediate = temp_list.index(float(a))+1 788 | 789 | else: 790 | intermediate = temp_list.index(str(a))+1 791 | 792 | new_var_name = self.operand_names.pop(0) 793 | self.code_string += '{} = {}.index({})+1\n'.format(new_var_name, temp_lname, a_name) 794 | self.list_stack.push(temp_list, temp_lname) 795 | self.operand_stack.push(intermediate, new_var_name) 796 | elif operator_name in ['[OP_LIST_MORE]', '[OP_LIST_LESS]', '[OP_LIST_MORE_EQUAL]', '[OP_LIST_LESS_EQUAL]']: 797 | new_list_name = self.list_names.pop(0) 798 | if operator_name == '[OP_LIST_MORE]': 799 | intermediate_list = [i for i in temp_list if self.intifint(self.to_float(i)) > a] 800 | self.code_string += '{new_list} = []\n\ 801 | for i in {temp}:\n\ 802 | if i > {a}:\n\ 803 | {new_list}.append(i)\n'.format(new_list=new_list_name, temp=temp_lname, a=a_name) 804 | elif operator_name == '[OP_LIST_LESS]': 805 | intermediate_list = [i for i in temp_list if self.intifint(self.to_float(i)) < a] 806 | # self.code_string += '{} = [i for i in {} if i < {}]\n'.format(new_list_name, temp_lname, a_name) 807 | self.code_string += '{new_list} = []\n\ 808 | for i in {temp}:\n\ 809 | if i < {a}:\n\ 810 | {new_list}.append(i)\n'.format(new_list=new_list_name, temp=temp_lname, a=a_name) 811 | elif operator_name == '[OP_LIST_MORE_EQUAL]': 812 | intermediate_list = [i for i in temp_list if self.intifint(self.to_float(i)) >= a] 813 | # self.code_string += '{} = [i for i in {} if i >= {}]\n'.format(new_list_name, temp_lname, a_name) 814 | self.code_string += '{new_list} = []\n\ 815 | for i in {temp}:\n\ 816 | if i >= {a}:\n\ 817 | {new_list}.append(i)\n'.format(new_list=new_list_name, temp=temp_lname, a=a_name) 818 | elif operator_name == '[OP_LIST_LESS_EQUAL]': 819 | intermediate_list = [i for i in temp_list if self.intifint(self.to_float(i)) <= a] 820 | # self.code_string += '{} = [i for i in {} if i <= {}]\n'.format(new_list_name, temp_lname, a_name) 821 | self.code_string += '{new_list} = []\n\ 822 | for i in {temp}:\n\ 823 | if i <= {a}:\n\ 824 | {new_list}.append(i)\n'.format(new_list=new_list_name, temp=temp_lname, a=a_name) 825 | self.list_stack.push(temp_list, temp_lname) 826 | self.list_stack.push(intermediate_list, new_list_name) 827 | elif operator_name == '[OP_LIST_MAX]': 828 | zizigo = temp_list.copy() 829 | # for i in range(len(zizigo)): 830 | # zizigo[i] = float(zizigo[i]) 831 | zizigo.sort() 832 | intermediate = zizigo[-a] 833 | new_var_name = self.operand_names.pop(0) 834 | new_list_name = self.list_names.pop(0) 835 | self.code_string += '{new_list}={temp_list}.copy()\n{new_list}.sort()\n{intermediate} = {new_list}[-{a}]\n'.format(new_list=new_list_name,temp_list=temp_lname,intermediate=new_var_name,a=a_name) 836 | self.list_stack.push(temp_list, temp_lname) 837 | self.operand_stack.push(intermediate, new_var_name) 838 | elif operator_name == '[OP_LIST_MIN]': 839 | zizigo = temp_list.copy() 840 | # for i in range(len(zizigo)): 841 | # zizigo[i] = float(zizigo[i]) 842 | zizigo.sort() 843 | intermediate = temp_list[a-1] 844 | new_var_name = self.operand_names.pop(0) 845 | new_list_name = self.list_names.pop(0) 846 | self.code_string += '{new_list}={temp_list}.copy()\n{new_list}.sort()\n{intermediate} = {new_list}[{a}-1]\n'.format(new_list=new_list_name,temp_list=temp_lname,intermediate=new_var_name,a=a_name) 847 | self.list_stack.push(temp_list, temp_lname) 848 | self.operand_stack.push(intermediate, new_var_name) 849 | elif operator_name == '[OP_LIST_GET_PERM]': 850 | intermediate_list = [str(i) for i in temp_list] 851 | if len(intermediate_list) > 10 or int(a) > 10: 852 | print("Memory issue") 853 | return -1, self.code_string 854 | new_list_name = self.list_names.pop(0) 855 | intermediate_list = list(itertools.permutations(intermediate_list, a)) 856 | intermediate_list = [''.join(num_list) for num_list in intermediate_list] 857 | intermediate_list = [str_num for str_num in intermediate_list if str_num[0] != '0'] 858 | self.code_string += "{intermediate_list} = [str(i) for i in {temp_list}]\n\ 859 | {intermediate_list} = list(itertools.permutations({intermediate_list}, {a}))\n\ 860 | {intermediate_list} = [''.join(num_list) for num_list in {intermediate_list}]\n\ 861 | {intermediate_list} = [str_num for str_num in {intermediate_list} if str_num[0] != '0']\n".format(intermediate_list=new_list_name, temp_list=temp_lname, a=a_name) 862 | if self.is_number(intermediate_list[0]): 863 | intermediate_list = [self.to_float(i) for i in intermediate_list] 864 | self.code_string += "{intermediate_list} = [float(i) for i in {intermediate_list}]\n".format(intermediate_list = new_list_name) 865 | 866 | self.list_stack.push(temp_list, temp_lname) 867 | self.list_stack.push(intermediate_list, new_list_name) 868 | elif operator_name == '[OP_LIST_GET_PRODUCT]': 869 | intermediate_list = [str(i) for i in temp_list] 870 | if len(intermediate_list) > 10 or int(a) > 6: 871 | print("Memory issue") 872 | return -1, self.code_string 873 | intermediate_list = list(itertools.product(intermediate_list, repeat=a)) 874 | intermediate_list = [''.join(num_list) for num_list in intermediate_list] 875 | intermediate_list = [str_num for str_num in intermediate_list if str_num[0] != '0'] 876 | new_list_name = self.list_names.pop(0) 877 | self.code_string += "{intermediate_list} = [str(i) for i in {temp_list}]\n\ 878 | {intermediate_list} = list(itertools.product({intermediate_list}, repeat={a}))\n\ 879 | {intermediate_list} = [''.join(num_list) for num_list in {intermediate_list}]\n\ 880 | {intermediate_list} = [str_num for str_num in {intermediate_list} if str_num[0] != '0']\n".format(intermediate_list=new_list_name, temp_list=temp_lname, a=a_name) 881 | if self.is_number(intermediate_list[0]): 882 | intermediate_list = [self.to_float(i) for i in intermediate_list] 883 | self.code_string += "{intermediate_list} = [float(i) for i in {intermediate_list}]\n".format(intermediate_list = new_list_name) 884 | self.list_stack.push(temp_list, temp_lname) 885 | self.list_stack.push(intermediate_list, new_list_name) 886 | 887 | else: 888 | pass 889 | 890 | elif operator_name in ['[OP_SET_UNION]', '[OP_SET_INTERSECT]', '[OP_SET_DIFFERENCE]', '[OP_LIST_COND_MAX_MIN]']:# input: list, list / output: list 891 | b_list, b_lname = self.list_stack.pop() 892 | a_list, a_lname = self.list_stack.pop() 893 | new_list_name = self.list_names.pop(0) 894 | if operator_name == '[OP_SET_UNION]': 895 | intermediate_list = list(set(a_list) | set(b_list)) 896 | self.code_string += '{} = list(set({}) | set({}))\n'.format(new_list_name, a_lname, b_lname) 897 | elif operator_name == '[OP_SET_INTERSECT]': 898 | intermediate_list = list(set(a_list) & set(b_list)) 899 | self.code_string += '{} = list(set({}) & set({}))\n'.format(new_list_name, a_lname, b_lname) 900 | elif operator_name == '[OP_SET_DIFFERENCE]': 901 | intermediate_list = list(set(a_list) - set(b_list)) 902 | self.code_string += '{} = list(set({}) - set({}))\n'.format(new_list_name, a_lname, b_lname) 903 | elif operator_name == '[OP_LIST_COND_MAX_MIN]': 904 | # a_list: List of items 905 | # b_list: List of conditions -> multiple of 3 906 | items_name_list = a_list.copy() 907 | 908 | # Process conditions 909 | # conditions: list[str], List of string conditions which is evaluated using `eval()` later 910 | # If an operand is a string, it must be wrapped with { } 911 | # ex) ["{A} < {B}", "{B} == 3", "{C} > {A}"] 912 | conditions = [] 913 | condition_list = b_list.copy() 914 | temp_stack = [] # Temporary stack for processing postfix conditions 915 | for index_, cond_ in enumerate(map(str, condition_list)): 916 | try: 917 | if cond_ in ("<", ">", "="): 918 | # Operator 919 | operand_right = temp_stack.pop() 920 | operand_left = temp_stack.pop() 921 | 922 | if cond_ == "=": 923 | # Convert a single equal sign to double equal sign 924 | cond_ = "==" 925 | 926 | conditions.append(f"{operand_left} {cond_} {operand_right}") 927 | 928 | else: 929 | # Operand 930 | if not cond_.isdigit(): 931 | # Wrap string operands with braces 932 | cond_ = "{" + cond_ + "}" 933 | 934 | temp_stack.append(cond_) 935 | 936 | except IndexError as e: 937 | # Expected an item from temp_stack, but temp_stack is empty 938 | raise AssertionError(f"error while processing {cond_} at {index_}:" 939 | f"expected an operand from stack") from e 940 | 941 | # temp_stack should be empty 942 | assert len(temp_stack) == 0, f"temp_stack({temp_stack}) is not empty" \ 943 | f"after processing all condition inputs" 944 | 945 | # Calculate combinations 946 | condition_found = False 947 | item_name_index_dict = {} 948 | for perm in itertools.permutations(range(1, len(items_name_list) + 1)): 949 | item_name_index_dict = dict( 950 | zip(items_name_list, perm)) # ex) {"A": 2, "B": 1, "C": 3} 951 | 952 | # Format strings from `conditions` 953 | # ex) "{A} < {B}" -> "3 < 2" 954 | formatted_conditions = [condition.format_map(item_name_index_dict) for condition in 955 | conditions] 956 | if all(map(eval, formatted_conditions)): 957 | # All conditions met 958 | condition_found = True 959 | break 960 | 961 | assert condition_found, f"no combination found" 962 | 963 | # Sort result 964 | intermediate_list = list(item_name_index_dict.keys()) 965 | intermediate_list.sort(key=item_name_index_dict.get, reverse=True) 966 | 967 | del item_name_index_dict 968 | 969 | self.code_string += \ 970 | f"global item_name_index_dict\n" \ 971 | f"items_name_list = {a_lname}.copy()\n" \ 972 | "conditions = []\n" \ 973 | f"condition_list = {b_lname}.copy()\n" \ 974 | "temp_stack = []\n" \ 975 | "for index_, cond_ in enumerate(map(str, condition_list)):\n" \ 976 | " if cond_ in (\"<\", \">\", \"=\"):\n" \ 977 | " operand_right = temp_stack.pop()\n" \ 978 | " operand_left = temp_stack.pop()\n" \ 979 | " if cond_ == \"=\":\n" \ 980 | " cond_ = \"==\"\n" \ 981 | " conditions.append(f\"{operand_left} {cond_} {operand_right}\")\n" \ 982 | " else:\n" \ 983 | " if not cond_.isdigit():\n" \ 984 | " cond_ = \"{\" + cond_ + \"}\"\n" \ 985 | " temp_stack.append(cond_)\n" \ 986 | "item_name_index_dict = {}\n" \ 987 | "for perm in itertools.permutations(range(1, len(items_name_list) + 1)):\n" \ 988 | " item_name_index_dict = dict(zip(items_name_list, perm))\n" \ 989 | " formatted_conditions = \\\n" \ 990 | " [condition.format_map(item_name_index_dict) for condition in conditions]\n" \ 991 | " if all(map(eval, formatted_conditions)):\n" \ 992 | " break\n" \ 993 | f"{new_list_name} = list(item_name_index_dict.keys())\n" \ 994 | f"{new_list_name}.sort(key=item_name_index_dict.get, reverse=True)\n" 995 | 996 | self.list_stack.push(a_list, a_lname) 997 | self.list_stack.push(b_list, b_lname) 998 | self.list_stack.push(intermediate_list, new_list_name) 999 | 1000 | elif operator_name == '[OP_LIST_DIVISIBLE]': # Return a new list which contains the numbers that are divisible by a in temp_list 1001 | a, a_name = self.operand_stack.pop() 1002 | temp_list, temp_lname = self.list_stack.pop() 1003 | new_list_name = self.list_names.pop(0) 1004 | intermediate_list = [] 1005 | a = int(a) 1006 | for i in temp_list: 1007 | i =int(i) 1008 | if i % a == 0: 1009 | intermediate_list.append(i) 1010 | self.code_string += "{intermediate_list} = []\n\ 1011 | {a} = int({a})\n\ 1012 | for i in {temp_list}:\n\ 1013 | i = int(i)\n\ 1014 | if i % {a} == 0:\n\ 1015 | {intermediate_list}.append(i)\n".format(intermediate_list=new_list_name, a=a_name, temp_list=temp_lname) 1016 | self.list_stack.push(temp_list, temp_lname) 1017 | self.list_stack.push(intermediate_list, new_list_name) 1018 | 1019 | elif operator_name == '[OP_LIST_FIND_NUM]': 1020 | a, a_name = self.operand_stack.pop() 1021 | temp_list, temp_lname = self.list_stack.pop() 1022 | new_var_name = self.operand_names.pop(0) 1023 | intermediate = 0 1024 | a = int(a) 1025 | for i in temp_list: 1026 | i = int(i) 1027 | if i == a: 1028 | intermediate = intermediate + 1 1029 | self.code_string += '{intermediate} = 0\n\ 1030 | {a} = int({a})\n\ 1031 | for i in {temp_list}:\n\ 1032 | i = int(i)\n\ 1033 | if i == {a}:\n\ 1034 | {intermediate} = {intermediate} + 1\n'.format(intermediate=new_var_name, temp_list=temp_lname, a=a_name) 1035 | self.list_stack.push(temp_list, temp_lname) 1036 | self.operand_stack.push(intermediate, new_var_name) 1037 | elif operator_name in ['[OP_LIST_ODD]', '[OP_LIST_EVEN]']: 1038 | b, b_name = self.operand_stack.pop() 1039 | a, a_name = self.operand_stack.pop() 1040 | new_list_name = self.list_names.pop(0) 1041 | b = self.intifint(b) 1042 | a = self.intifint(a) 1043 | intermediate_list = [] 1044 | self.code_string += "{intermediate_list} = []\n".format(intermediate_list=new_list_name) 1045 | if operator_name == '[OP_LIST_ODD]': 1046 | if a%2==0: 1047 | for i in range(a+1, b+1, 2): 1048 | intermediate_list.append(i) 1049 | else: 1050 | for i in range(a, b+1, 2): 1051 | intermediate_list.append(i) 1052 | self.code_string += "if {a}%2==0:\n".format(a=a_name) 1053 | elif operator_name == '[OP_LIST_EVEN]': 1054 | if a%2!=0: 1055 | for i in range(a+1, b+1, 2): 1056 | intermediate_list.append(i) 1057 | else: 1058 | for i in range(a, b+1, 2): 1059 | intermediate_list.append(i) 1060 | self.code_string += "if {a}%2!=0:\n".format(a=a_name) 1061 | 1062 | self.code_string += " for i in range({a}+1, {b}+1, 2):\n\ 1063 | {intermediate_list}.append(i)\n\ 1064 | else:\n\ 1065 | for i in range({a}, {b}+1, 2):\n\ 1066 | {intermediate_list}.append(i)\n".format(intermediate_list=new_list_name, a=a_name, b=b_name) 1067 | 1068 | self.list_stack.push(intermediate_list, new_list_name) 1069 | 1070 | elif operator_info[1]==3: 1071 | if operator_name == '[OP_LIST_ARANGE]': 1072 | c, c_name = self.operand_stack.pop() 1073 | b, b_name = self.operand_stack.pop() 1074 | a, a_name = self.operand_stack.pop() 1075 | c = self.intifint(c) 1076 | b = self.intifint(b) 1077 | a = self.intifint(a) 1078 | list_name = self.list_names.pop(0) 1079 | intermediate_list = [i for i in range(a, b + 1, c)] 1080 | self.code_string += '{} = [i for i in range({}, {} + 1, {})]\n'.format(list_name, a_name, b_name, c_name) 1081 | self.list_stack.push(intermediate_list, list_name) 1082 | elif operator_name == '[OP_LIST_FIND_UNK]': 1083 | b, b_name = self.operand_stack.pop() 1084 | a, a_name = self.operand_stack.pop() 1085 | temp_list, temp_lname = self.list_stack.pop() 1086 | a = str(a) 1087 | b = str(b) 1088 | unk_idx = a.index(b) 1089 | intermediate = [] 1090 | for elem in temp_list: 1091 | elem = str(elem) 1092 | intermediate.append(int(elem[unk_idx])) 1093 | intermediate = list(set(intermediate)) 1094 | if len(intermediate) == 1: 1095 | intermediate = intermediate[0] 1096 | 1097 | if isinstance(intermediate, list): 1098 | new_list_name = self.list_names.pop(0) 1099 | self.list_stack.push(temp_list, temp_lname) 1100 | self.list_stack.push(intermediate, new_list_name) 1101 | self.code_string += '{a} = str({a})\n\ 1102 | {b} = str({b})\n\ 1103 | unk_idx = {a}.index({b})\n\ 1104 | {intermediate_list} = []\n\ 1105 | for elem in {temp_list}:\n\ 1106 | elem = str(elem)\n\ 1107 | {intermediate_list}.append(int(elem[unk_idx]))\n\ 1108 | {intermediate_list} = list(set({intermediate_list}))\n'.format(a=a_name, b=b_name, intermediate_list=new_list_name, temp_list=temp_lname) 1109 | else: 1110 | new_var_name = self.operand_names.pop(0) 1111 | self.list_stack.push(temp_list, temp_lname) 1112 | self.operand_stack.push(intermediate, new_var_name) 1113 | self.code_string += '{a} = str({a})\n\ 1114 | {b} = str({b})\n\ 1115 | unk_idx = {a}.index({b})\n\ 1116 | {intermediate} = 0\n\ 1117 | for elem in {temp_list}:\n\ 1118 | elem = str(elem)\n\ 1119 | {intermediate} = int(elem[unk_idx])\n'.format(a=a_name, b=b_name, intermediate=new_var_name, temp_list=temp_lname) 1120 | elif operator_name == '[OP_LIST_DIVIDE_AND_REMAIN]': 1121 | b, b_name = self.operand_stack.pop() 1122 | a, a_name = self.operand_stack.pop() 1123 | b = self.intifint(b) 1124 | a = self.intifint(a) 1125 | temp_list, temp_lname = self.list_stack.pop() 1126 | new_list_name = self.list_names.pop(0) 1127 | intermediate_list = [] 1128 | a = int(a) 1129 | b = int(b) 1130 | if b < 0: 1131 | b = b + a 1132 | for i in temp_list: 1133 | i = int(i) 1134 | if i%a == b: 1135 | intermediate_list.append(i) 1136 | #print('intermediate_list', intermediate_list) 1137 | self.code_string += "{intermediate_list} = [] \n\ 1138 | {a} = int({a})\n\ 1139 | {b} = int({b})\n\ 1140 | if {b} < 0:\n\ 1141 | {b} = {b} + {a}\n\ 1142 | for i in {temp_list}:\n\ 1143 | i = int(i)\n\ 1144 | if i%{a} == {b}:\n\ 1145 | {intermediate_list}.append(i)\n".format(intermediate_list=new_list_name, a=a_name, b=b_name, temp_list=temp_lname) 1146 | self.list_stack.push(temp_list, temp_lname) 1147 | self.list_stack.push(intermediate_list, new_list_name) 1148 | elif operator_name == '[OP_LIST_SEARCH_FIXED_DIGIT]': 1149 | b, b_name = self.operand_stack.pop() 1150 | a, a_name = self.operand_stack.pop() 1151 | b = self.intifint(b) 1152 | a = self.intifint(a) 1153 | temp_list, temp_lname = self.list_stack.pop() 1154 | new_list_name = self.list_names.pop(0) 1155 | intermediate_list = [] 1156 | a = int(a) 1157 | b = int(b) 1158 | for i in temp_list: 1159 | i = int(i) 1160 | if (i // a) % 10 == b: 1161 | intermediate_list.append(i) 1162 | self.code_string += "{intermediate_list} = [] \n\ 1163 | {a} = int({a})\n\ 1164 | {b} = int({b})\n\ 1165 | for i in {temp_list}:\n\ 1166 | i = int(i)\n\ 1167 | if (i//{a})%10 == {b}:\n\ 1168 | {intermediate_list}.append(i)\n".format(intermediate_list=new_list_name, a=a_name, b=b_name, temp_list=temp_lname) 1169 | self.list_stack.push(temp_list, temp_lname) 1170 | self.list_stack.push(intermediate_list, new_list_name) 1171 | elif operator_name == '[OP_LIST_COND_BIG_SMALL]': 1172 | target_list, target_name = self.list_stack.pop() 1173 | condition_list, condition_name = self.list_stack.pop() 1174 | entity_list, entity_name = self.list_stack.pop() 1175 | new_list_name = self.list_names.pop(0) 1176 | 1177 | from queue import Queue 1178 | 1179 | input_dict = {i: cnt for cnt, i in enumerate(entity_list)} 1180 | 1181 | adj_mat = [[0 for _ in range(len(entity_list))] for _ in range(len(entity_list))] 1182 | is_visited = [[0 for _ in range(len(entity_list))] for _ in range(len(entity_list))] 1183 | 1184 | que = Queue() 1185 | 1186 | iterate_num = len(condition_list)//3 1187 | 1188 | for i in range(iterate_num): 1189 | operand_1 = condition_list[i*3] 1190 | operand_2 = condition_list[i*3 + 1] 1191 | 1192 | operand_1_id = input_dict[operand_1] 1193 | operand_2_id = input_dict[operand_2] 1194 | 1195 | operator = condition_list[i*3+2] 1196 | 1197 | if operator == '>': 1198 | adj_mat[operand_1_id][operand_2_id] = 1 1199 | is_visited[operand_1_id][operand_2_id] = 1 1200 | que.put((operand_1_id, operand_2_id)) 1201 | 1202 | adj_mat[operand_2_id][operand_1_id] = -1 1203 | is_visited[operand_2_id][operand_1_id] = 1 1204 | que.put((operand_2_id, operand_1_id)) 1205 | 1206 | elif operator == '<': 1207 | adj_mat[operand_1_id, operand_2_id] = -1 1208 | is_visited[operand_1_id][operand_2_id] = 1 1209 | que.put((operand_1_id, operand_2_id)) 1210 | 1211 | adj_mat[operand_2_id, operand_1_id] = 1 1212 | is_visited[operand_2_id][operand_1_id] = 1 1213 | que.put((operand_2_id, operand_1_id)) 1214 | 1215 | while not que.empty(): 1216 | operand_1, operand_2 = que.get() 1217 | 1218 | if adj_mat[operand_1][operand_2] == 1: 1219 | for i in range(0, len(entity_list)): 1220 | if (adj_mat[operand_1][i] == -1) and (not is_visited[operand_2][i]): 1221 | adj_mat[operand_2][i] = -1 1222 | adj_mat[i][operand_2] = 1 1223 | is_visited[operand_2][i] = 1 1224 | is_visited[i][operand_2] = 1 1225 | que.put((operand_2, i)) 1226 | que.put((i, operand_2)) 1227 | 1228 | for i in range(0, len(entity_list)): 1229 | if (adj_mat[operand_2][i] == 1) and (not is_visited[operand_1][i]): 1230 | adj_mat[operand_1][i] = 1 1231 | adj_mat[i][operand_1] = -1 1232 | is_visited[operand_1][i] = 1 1233 | is_visited[i][operand_1] = 1 1234 | que.put((operand_1, i)) 1235 | que.put((i, operand_1)) 1236 | 1237 | if adj_mat[operand_1][operand_2] == -1: 1238 | for i in range(0, len(entity_list)): 1239 | if (adj_mat[operand_1][i] == 1) and (not is_visited[i][operand_2]): 1240 | adj_mat[i][operand_2] = -1 1241 | adj_mat[operand_2][i] = 1 1242 | is_visited[i][operand_2] = 1 1243 | is_visited[operand_2][i] = 1 1244 | que.put((i, operand_2)) 1245 | que.put((operand_2, i)) 1246 | 1247 | for i in range(0, len(entity_list)): 1248 | if (adj_mat[operand_2][i] == -1) and (not is_visited[operand_1][i]): 1249 | adj_mat[operand_1][i] = -1 1250 | adj_mat[i][operand_1] = 1 1251 | is_visited[i][operand_1] = 1 1252 | is_visited[operand_1][i] = 1 1253 | que.put(operand_1, i) 1254 | que.put(i, operand_1) 1255 | 1256 | operand_1 = target_list[0] 1257 | operand_2 = target_list[1] 1258 | 1259 | operand_1_id = input_dict[operand_1] 1260 | operand_2_id = input_dict[operand_2] 1261 | 1262 | if adj_mat[operand_1_id][operand_2_id] == -1: 1263 | intermediate_list = [operand_2, operand_1] 1264 | else: 1265 | intermediate_list = [operand_1, operand_2] 1266 | 1267 | self.list_stack.push(intermediate_list, new_list_name) 1268 | 1269 | self.code_string += "from queue import Queue\n\ 1270 | input_dict = dict()\n\ 1271 | for cnt, i in enumerate({entity_list}):\n\ 1272 | input_dict[i] = cnt\n\ 1273 | adj_mat = []\n\ 1274 | for _ in range(len({entity_list})):\n\ 1275 | temp_list = []\n\ 1276 | for _ in range(len({entity_list})):\n\ 1277 | temp_list.append(0)\n\ 1278 | adj_mat.append(temp_list)\n\ 1279 | is_visited = []\n\ 1280 | for _ in range(len({entity_list})):\n\ 1281 | temp_list = []\n\ 1282 | for _ in range(len({entity_list})):\n\ 1283 | temp_list.append(0)\n\ 1284 | is_visited.append(temp_list)\n\ 1285 | que = Queue()\n\ 1286 | iterate_num = len({condition})//3\n\ 1287 | for i in range(iterate_num):\n\ 1288 | operand_1 = {condition}[i*3]\n\ 1289 | operand_2 = {condition}[i*3 + 1]\n\ 1290 | operand_1_id = input_dict[operand_1]\n\ 1291 | operand_2_id = input_dict[operand_2]\n\ 1292 | operator = {condition}[i*3+2]\n\ 1293 | if operator == '>':\n\ 1294 | adj_mat[operand_1_id][operand_2_id] = 1\n\ 1295 | is_visited[operand_1_id][operand_2_id] = 1\n\ 1296 | que.put((operand_1_id, operand_2_id))\n\ 1297 | adj_mat[operand_2_id][operand_1_id] = -1\n\ 1298 | is_visited[operand_2_id][operand_1_id] = 1\n\ 1299 | que.put((operand_2_id, operand_1_id))\n\ 1300 | elif operator == '<':\n\ 1301 | adj_mat[operand_1_id, operand_2_id] = -1\n\ 1302 | is_visited[operand_1_id][operand_2_id] = 1\n\ 1303 | que.put((operand_1_id, operand_2_id))\n\ 1304 | adj_mat[operand_2_id, operand_1_id] = 1\n\ 1305 | is_visited[operand_2_id][operand_1_id] = 1\n\ 1306 | que.put((operand_2_id, operand_1_id))\n\ 1307 | while not que.empty():\n\ 1308 | operand_1, operand_2 = que.get()\n\ 1309 | if adj_mat[operand_1][operand_2] == 1:\n\ 1310 | for i in range(0, len({entity_list})):\n\ 1311 | if (adj_mat[operand_1][i] == -1) and (not is_visited[operand_2][i]):\n\ 1312 | adj_mat[operand_2][i] = -1\n\ 1313 | adj_mat[i][operand_2] = 1\n\ 1314 | is_visited[operand_2][i] = 1\n\ 1315 | is_visited[i][operand_2] = 1\n\ 1316 | que.put((operand_2, i))\n\ 1317 | que.put((i, operand_2))\n\ 1318 | for i in range(0, len({entity_list})):\n\ 1319 | if (adj_mat[operand_2][i] == 1) and (not is_visited[operand_1][i]):\n\ 1320 | adj_mat[operand_1][i] = 1\n\ 1321 | adj_mat[i][operand_1] = -1\n\ 1322 | is_visited[operand_1][i] = 1\n\ 1323 | is_visited[i][operand_1] = 1\n\ 1324 | que.put((operand_1, i))\n\ 1325 | que.put((i, operand_1))\n\ 1326 | if adj_mat[operand_1][operand_2] == -1:\n\ 1327 | for i in range(0, len({entity_list})):\n\ 1328 | if (adj_mat[operand_1][i] == 1) and (not is_visited[i][operand_2]):\n\ 1329 | adj_mat[i][operand_2] = -1\n\ 1330 | adj_mat[operand_2][i] = 1\n\ 1331 | is_visited[i][operand_2] = 1\n\ 1332 | is_visited[operand_2][i] = 1\n\ 1333 | que.put((i, operand_2))\n\ 1334 | que.put((operand_2, i))\n\ 1335 | for i in range(0, len({entity_list})):\n\ 1336 | if (adj_mat[operand_2][i] == -1) and (not is_visited[operand_1][i]):\n\ 1337 | adj_mat[operand_1][i] = -1\n\ 1338 | adj_mat[i][operand_1] = 1\n\ 1339 | is_visited[i][operand_1] = 1\n\ 1340 | is_visited[operand_1][i] = 1\n\ 1341 | que.put(operand_1, i)\n\ 1342 | que.put(i, operand_1)\n\ 1343 | operand_1 = {target}[0]\n\ 1344 | operand_2 = {target}[1]\n\ 1345 | operand_1_id = input_dict[operand_1]\n\ 1346 | operand_2_id = input_dict[operand_2]\n\ 1347 | if adj_mat[operand_1_id][operand_2_id] == -1:\n\ 1348 | {intermediate_list} = [operand_2, operand_1]\n\ 1349 | else:\n\ 1350 | {intermediate_list} = [operand_2, operand_1]\n".format(entity_list=entity_name, target=target_name, condition=condition_name, intermediate_list=new_list_name) 1351 | else: 1352 | print("not defined") 1353 | 1354 | else: # if operand - scalar value 1355 | # var_name = self.operand_names.pop(0) 1356 | # self.operand_stack.push(i, var_name) 1357 | 1358 | var_name = self.operand_names.pop(0) 1359 | 1360 | if self.is_number(i): 1361 | i = self.to_float(i) 1362 | if i == int(i): 1363 | i = int(i) 1364 | self.code_string += '{} = {}\n'.format(var_name, i) 1365 | #if self.is_fraction(i): 1366 | # self.code_string += '{var} = round({var}+1e-10, 2)\n'.format(var=var_name) 1367 | # i = round(self.to_float(i)+1e-10, 2) 1368 | else: 1369 | self.code_string += "{} = '{}'\n".format(var_name, i) 1370 | 1371 | self.operand_stack.push(i, var_name) 1372 | 1373 | 1374 | result, name = self.operand_stack.pop() 1375 | loc = {} 1376 | # print(self.code_string) 1377 | exec(self.code_string, globals(), loc) 1378 | result = loc[name] 1379 | 1380 | str(result) # Raise Time out error for error hanlding 1381 | 1382 | try: 1383 | if int(result) != self.to_float(result): # float 1384 | result = '{:.2f}'.format(round(result+1e-10, 2)) 1385 | if str(result)[-3:] == ".00": 1386 | result = int(result[:-3]) 1387 | self.code_string += "print(int(eval('{:.2f}'.format(round(%s+1e-10,2)))))"%name 1388 | else: 1389 | self.code_string += "print('{:.2f}'.format(round(%s+1e-10,2)))"% name 1390 | else: # int 1391 | result = int(result) 1392 | self.code_string += 'print(int({}))'.format(name) 1393 | except: # string 1394 | name = name.replace('(', '') 1395 | name = name.replace(')', '') 1396 | self.code_string += 'print({})'.format(name) 1397 | 1398 | return result, self.code_string 1399 | 1400 | -------------------------------------------------------------------------------- /solution/test.py: -------------------------------------------------------------------------------- 1 | from converter import PostfixConverter 2 | 3 | converter = PostfixConverter() 4 | 5 | # solution = "12 53 1 [OP_LIST_ARANGE] 2 [OP_LIST_DIVISIBLE] [OP_SET_DIFFERENCE] [OP_LIST_MEAN]" 6 | solution = "0.72 0.46 [OP_SUB] 2 [OP_DIV]" 7 | ans, code = converter.convert(solution) 8 | 9 | print(f"Solution: {solution}\n") 10 | print(f"Answer: {ans}\n") 11 | print(f"Code:") 12 | print(code) --------------------------------------------------------------------------------