├── evaluation ├── module2_formula_rearrangement │ └── module2_description ├── module4_question_text_generation │ └── module4_description ├── module3_identifier_value_generation │ ├── module3_description │ ├── unit_test_module3.py │ └── Latex2Sympy_transformations.csv ├── module5_solution_value_and_unit_check │ └── module5_description ├── module1_formula_and_identifier_retrieval │ ├── module1_description │ ├── Identifier_Unit_Wikidata_Properties_evaluation.xlsx │ ├── GoldID-QID_correspondence.csv │ ├── unit_test_module.csv │ ├── Identifier_Unit_Wikidata_Properties_evaluator.py │ └── Identifier_Unit_Wikidata_Properties_evaluation.csv ├── PhysWikiQuiz_Challenges.pdf ├── ResearchQuestionsTasks.docx ├── PhysWikiQuizvsCompetitors.csv ├── current_challenges.txt ├── module_workflow │ ├── unit_test_module_workflow_latex2sympy_evaluated(0).pdf │ ├── unit_test_module_workflow_latex2sympy_evaluated(0).xlsx │ ├── demo_examples.csv │ ├── log_properties.csv │ ├── unit_test_module_workflow_empty.csv │ ├── unit_test_module_workflow_manual(0).csv │ ├── LaTeX2Sympy_vs._LaCASt.tgn │ ├── unit_test_module_workflow_latex2sympy_evaluated(0).csv │ ├── integration_test.py │ └── unit_test_module_workflow_latex2sympy_generated(0).csv ├── ConceptComparison.csv ├── ResearchQuestionsV1.txt ├── sample_IDs.csv ├── module_workflow.txt └── Applied_questions.csv ├── images ├── N_generated_formula.png ├── N_questions_generated.png ├── PhysWikiQuiz_workflow.png ├── PhysWikiQuiz_acceleration.png ├── PhysWikiQuiz_demo_speed.gif ├── unit_test_module_workflow.png ├── PhysWikiQuiz-Workflow_white.png ├── PhysWikiQuiz_demo_acceleration.gif └── PhysWikiQuiz_workflow_acceleration.png ├── login ├── templates │ ├── ._signup.html │ ├── profile.html │ ├── index.html │ ├── login.html │ ├── signup.html │ ├── teacher.html │ ├── student.html │ └── base.html ├── models.py ├── __init__.py ├── static │ └── style.css ├── auth.py ├── utils │ └── sql_tools.py └── main.py ├── old ├── PhysWikiQuiz-Screenshot.jpg ├── PhysWikiQuiz-Workflow.png ├── PhysWikiQuiz-Screenshot_correction.jpg ├── module1_identifier_unit_retrieval.py ├── module_outputs0.py └── module0_formula_and_identifier_retrieval.py ├── PhysWikiQuiz-Screenshot_example.png ├── latex_cleanings_argument.txt ├── .gitignore ├── requirements.txt ├── Dockerfile ├── user-config.py ├── demo └── demo_examples.csv ├── cache.json ├── .github └── workflows │ ├── docker-image.yml │ └── docker-publish.yml ├── latex_cleanings_simple_identifier.csv ├── latex_cleanings_simple_formula.csv ├── Citation.bib ├── benchmark_cache.py ├── module6_explanation_text_generation.py ├── module_unit_tests.py ├── module4_question_text_generation.py ├── module2_formula_rearrangement.py ├── static └── style.css ├── templates ├── student.html ├── teacher.html ├── my-form.html └── select.html ├── module3_identifier_value_generation.py ├── module5_solution_value_and_unit_check.py ├── module_outputs.py ├── module_workflow.py ├── app.py ├── module1_formula_and_identifier_retrieval.py ├── LICENSE └── README.md /evaluation/module2_formula_rearrangement/module2_description: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /evaluation/module4_question_text_generation/module4_description: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /evaluation/module3_identifier_value_generation/module3_description: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /evaluation/module5_solution_value_and_unit_check/module5_description: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /evaluation/module1_formula_and_identifier_retrieval/module1_description: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/N_generated_formula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/N_generated_formula.png -------------------------------------------------------------------------------- /login/templates/._signup.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/login/templates/._signup.html -------------------------------------------------------------------------------- /old/PhysWikiQuiz-Screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/old/PhysWikiQuiz-Screenshot.jpg -------------------------------------------------------------------------------- /old/PhysWikiQuiz-Workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/old/PhysWikiQuiz-Workflow.png -------------------------------------------------------------------------------- /images/N_questions_generated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/N_questions_generated.png -------------------------------------------------------------------------------- /images/PhysWikiQuiz_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/PhysWikiQuiz_workflow.png -------------------------------------------------------------------------------- /PhysWikiQuiz-Screenshot_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/PhysWikiQuiz-Screenshot_example.png -------------------------------------------------------------------------------- /images/PhysWikiQuiz_acceleration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/PhysWikiQuiz_acceleration.png -------------------------------------------------------------------------------- /images/PhysWikiQuiz_demo_speed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/PhysWikiQuiz_demo_speed.gif -------------------------------------------------------------------------------- /images/unit_test_module_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/unit_test_module_workflow.png -------------------------------------------------------------------------------- /evaluation/PhysWikiQuiz_Challenges.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/evaluation/PhysWikiQuiz_Challenges.pdf -------------------------------------------------------------------------------- /evaluation/ResearchQuestionsTasks.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/evaluation/ResearchQuestionsTasks.docx -------------------------------------------------------------------------------- /images/PhysWikiQuiz-Workflow_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/PhysWikiQuiz-Workflow_white.png -------------------------------------------------------------------------------- /images/PhysWikiQuiz_demo_acceleration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/PhysWikiQuiz_demo_acceleration.gif -------------------------------------------------------------------------------- /old/PhysWikiQuiz-Screenshot_correction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/old/PhysWikiQuiz-Screenshot_correction.jpg -------------------------------------------------------------------------------- /images/PhysWikiQuiz_workflow_acceleration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/images/PhysWikiQuiz_workflow_acceleration.png -------------------------------------------------------------------------------- /latex_cleanings_argument.txt: -------------------------------------------------------------------------------- 1 | \boldsymbol{x} 2 | \mathrm{x} 3 | \mathbf{x} 4 | \mathsymbol{x} 5 | \vec{x} 6 | \hat{x} 7 | \text{x} 8 | \mathcal{x} 9 | \mathit{x} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /evaluation/module_workflow/pywikibot.lwp 2 | /evaluation/module_workflow/latex_cleanings_argument.txt 3 | /evaluation/module_workflow/latex_cleanings_simple.csv 4 | -------------------------------------------------------------------------------- /evaluation/PhysWikiQuizvsCompetitors.csv: -------------------------------------------------------------------------------- 1 | System,Mr Watts Physics,physQuiz Equations,PhysWikiQuiz 2 | Concepts,36,8,469 (Wikidata) 3 | Questions per concept,20,20,unlimited 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.2 2 | requests==2.26.0 3 | pywikibot==7.7.2 4 | wikitextparser==0.51.1 5 | SPARQLWrapper==1.8.2 6 | latex2sympy2==1.6.2 7 | sympy==1.7.1 8 | pandas==1.2.1 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | WORKDIR /app 4 | COPY ./requirements.txt /app/requirements.txt 5 | RUN pip install -r requirements.txt 6 | COPY . /app 7 | ENTRYPOINT ["python", "app.py"] -------------------------------------------------------------------------------- /user-config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This is a sample file. You should use generate_user_files.py 4 | # to create your user-config.py file. 5 | 6 | mylang = 'en' 7 | family = 'wikipedia' -------------------------------------------------------------------------------- /evaluation/current_challenges.txt: -------------------------------------------------------------------------------- 1 | #Example item issues: 2 | #-Hooke's law 3 | #-mechanical impedance 4 | #-tangential velocity 5 | 6 | #Additional issues: 7 | #-phase velocity (Q13824) 8 | #-mechanical energy (Q184550) -------------------------------------------------------------------------------- /evaluation/module_workflow/unit_test_module_workflow_latex2sympy_evaluated(0).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/evaluation/module_workflow/unit_test_module_workflow_latex2sympy_evaluated(0).pdf -------------------------------------------------------------------------------- /evaluation/module_workflow/unit_test_module_workflow_latex2sympy_evaluated(0).xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/evaluation/module_workflow/unit_test_module_workflow_latex2sympy_evaluated(0).xlsx -------------------------------------------------------------------------------- /login/templates/profile.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |

5 | Welcome, {{name}}! 6 |

7 | Teacher 8 | Student 9 | {% endblock %} -------------------------------------------------------------------------------- /evaluation/module1_formula_and_identifier_retrieval/Identifier_Unit_Wikidata_Properties_evaluation.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gipplab/PhysWikiQuiz/HEAD/evaluation/module1_formula_and_identifier_retrieval/Identifier_Unit_Wikidata_Properties_evaluation.xlsx -------------------------------------------------------------------------------- /demo/demo_examples.csv: -------------------------------------------------------------------------------- 1 | QID,Name 2 | Q11376,acceleration 3 | Q161254,angular momentum 4 | Q11402,force 5 | Q11652,frequency 6 | Q497332,jerk 7 | Q46276,kinetic energy 8 | Q35875,mass-energy equivalence 9 | Q41273,momentum 10 | Q3711325,speed 11 | Q1111,electric charge -------------------------------------------------------------------------------- /evaluation/ConceptComparison.csv: -------------------------------------------------------------------------------- 1 | Concept;phyQuiz;Mr Watt;PhysWikiQuiz 2 | kinetic energy;x;x;x 3 | gravitational potential energy;x;x;x 4 | elastic potential energy;x;x;- 5 | power;x;x;x 6 | density;x;x;x 7 | specific heat capacity;x;x;x 8 | charge;x;-;x 9 | current;x;x;- 10 | -------------------------------------------------------------------------------- /cache.json: -------------------------------------------------------------------------------- 1 | {"concept": "speed", "question": "What is the position vector R, given velocity v = 6 m s^-1, duration t = 2 s ?", "question_generated": true, "correct_value": "12.0", "correct_unit": "m", "explanation": "Solution from www.wikidata.org/wiki/Q11465 formula R = t*v with 12.0 m = 2 s * 6 m s^-1 ."} -------------------------------------------------------------------------------- /login/models.py: -------------------------------------------------------------------------------- 1 | from flask_login import UserMixin 2 | from __init__ import db 3 | 4 | class User(UserMixin, db.Model): 5 | id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy 6 | email = db.Column(db.String(100), unique=True) 7 | password = db.Column(db.String(100)) 8 | name = db.Column(db.String(1000)) -------------------------------------------------------------------------------- /evaluation/module_workflow/demo_examples.csv: -------------------------------------------------------------------------------- 1 | QID;Name 2 | Q11376;acceleration 3 | Q161254;angular momentum 4 | Q11402;force 5 | Q11652;frequency 6 | Q170282;Hooke's law 7 | Q497332;jerk 8 | Q46276;kinetic energy 9 | Q35875;mass-energy equivalence 10 | Q6421317;mechanical impedance 11 | Q41273;momentum 12 | Q3711325;speed 13 | Q103715245;tangential velocity 14 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Build the Docker image 18 | run: docker build . --file Dockerfile --tag my-image-name:$(date +%s) 19 | -------------------------------------------------------------------------------- /evaluation/module_workflow/log_properties.csv: -------------------------------------------------------------------------------- 1 | Property;Example 2 | Concept Name;frequency 3 | Concept QID;Q11652 4 | Defining formula;f = \frac{1}{T} 5 | Formula unit;\mathsf{T}^{-1} 6 | Identifier properties;[('frequency', 'f', 's^-1'), ('period', 'T', 's')] 7 | Properties in;P7235 8 | Identifiers sympy;(f, T) 9 | Formula sympy;1/T 10 | Sympy rhs;1 11 | Question text;What is the frequency f, given period T = 1 s ? 12 | -------------------------------------------------------------------------------- /latex_cleanings_simple_identifier.csv: -------------------------------------------------------------------------------- 1 | \alpha,a 2 | \beta,b 3 | \gamma,g 4 | \Gamma,G 5 | \delta,d 6 | \Delta,D 7 | \epsilon,e 8 | \varepsilon,e 9 | \zeta,z 10 | \eta,h 11 | \theta,t 12 | \vartheta,t 13 | \Theta,T 14 | \iota,j 15 | \kappa,k 16 | \lambda,l 17 | \mu,m 18 | \nu,n 19 | \xi,x 20 | \Xi,x 21 | \pi,p 22 | \Pi,p 23 | \rho,R 24 | \varrho,R 25 | \sigma,s 26 | \Sigma,S 27 | \tau,t 28 | \upsilon,u 29 | \Upsilon,U 30 | \phi,v 31 | \varphi,v 32 | \Phi,V 33 | \chi,x 34 | \psi,p 35 | \Psi,P 36 | \omega,w 37 | \Omega,O 38 | c,C 39 | E,e 40 | r,R 41 | I,J 42 | \boldsymbol, 43 | {, 44 | }, 45 | , -------------------------------------------------------------------------------- /evaluation/module3_identifier_value_generation/unit_test_module3.py: -------------------------------------------------------------------------------- 1 | #import latex2sympy 2 | #from process_latex import process_sympy 3 | from latex2sympy2 import latex2sympy 4 | 5 | defining_formula = input('Enter defining formula: ') 6 | 7 | try: 8 | formula_sympy = latex2sympy(defining_formula) 9 | #formula_sympy = latex2sympy.strToSympy(defining_formula) 10 | #formula_sympy = process_sympy(defining_formula) 11 | print('\nSympy format is') 12 | print(str(formula_sympy)) 13 | except: 14 | print('\nFormula could not be parsed from LaTeX to Sympy') 15 | 16 | print('\nend') -------------------------------------------------------------------------------- /latex_cleanings_simple_formula.csv: -------------------------------------------------------------------------------- 1 | c, C 2 | c ,C 3 | E, e 4 | E ,e 5 | r, R 6 | r ,R 7 | \cdot,* 8 | \times,* 9 | \partial, 10 | {d ,{ 11 | I,J 12 | \boldsymbol, 13 | \alpha,a 14 | \beta,b 15 | \gamma,g 16 | \Gamma,G 17 | \delta,d 18 | \Delta,D 19 | \epsilon,e 20 | \varepsilon,ee 21 | \zeta,z 22 | \eta,h 23 | \theta,t 24 | \vartheta,t 25 | \Theta,T 26 | \iota,j 27 | \kappa,k 28 | \lambda,l 29 | \mu,m 30 | \nu,n 31 | \xi,x 32 | \Xi,x 33 | \pi,p 34 | \Pi,p 35 | \rho,R 36 | \varrho,R 37 | \sigma,s 38 | \Sigma,S 39 | \tau,t 40 | \upsilon,u 41 | \Upsilon,U 42 | \phi,v 43 | \varphi,v 44 | \Phi,V 45 | \chi,x 46 | \psi,p 47 | \Psi,P 48 | \omega,w 49 | \Omega,O -------------------------------------------------------------------------------- /Citation.bib: -------------------------------------------------------------------------------- 1 | @inproceedings{Scharpf2022a, 2 | title = {Collaborative and AI-aided Exam Question Generation using Wikidata in Education}, 3 | author = {Scharpf, Philipp and Schubotz, Moritz and Spitz, Andreas and Greiner-Petter, Andre and Gipp, Bela}, 4 | year = 2022, 5 | month = {October}, 6 | booktitle = {Proceedings of the 3rd Wikidata Workshop (Wikidata 2022) co-located with the 21th International Semantic Web Conference (ISWC 2022)}, 7 | publisher = {{CEUR} Workshop Proceedings}, 8 | address = {Hangzhou, China (virtual)}, 9 | doi = {10.13140/RG.2.2.30988.18568}, 10 | topic = {mathir} 11 | } -------------------------------------------------------------------------------- /login/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |

5 | PhysWikiQuiz 6 |

7 |

8 | Teacher and Student Login 9 |

10 | {% endblock %} 11 | 12 | 13 | ---------------Folder project name 14 | ├── __init__.py # setup your app 15 | ├── main.py # the non-auth routes for your app 16 | ├── auth.py # the auth routes for your app 17 | ├── models.py # your user model 18 | ├── db.sqlite # your database 19 | └── templates 20 | ├── base.html # contains common layout and links 21 | ├── index.html # show the home page 22 | ├── login.html # show the login form 23 | ├── profile.html # show the profile page 24 | └── signup.html # show the signup form 25 | -------------------------------------------------------------------------------- /evaluation/ResearchQuestionsV1.txt: -------------------------------------------------------------------------------- 1 | Performance evaluation of: 2 | 3 | - Retrieval of units from Wikidata items (Pywikibot or SPARQL) 4 | - Retrieval of units from Wikipedia articles (AnnoMathTeX or unsupervised) 5 | - Generation of identifier values 6 | - Consistency check of identifier units 7 | - Solution assessment (value or unit wrong) 8 | - Rearranging equations using CAS 9 | 10 | For MathMLben Formula Concept testset check: 11 | (mathmlben.wmflabs.org - GoldID 310-375) 12 | 13 | - How many identifier items have unit properties? Which ones? (list the properties, discuss their strengths and weaknesses) 14 | - Can the unit information be used to make a unit consistency check for left- and right-hand side of the formula? 15 | - How to (semi-)automatically calculate/retrieve reasonable values for the identifiers? 16 | - How many constants can be retrieved from Wikidata? Just values or units also? 17 | - What are the issues in each step? 18 | - How can they be adressed? -------------------------------------------------------------------------------- /benchmark_cache.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import json 3 | import module1_formula_and_identifier_retrieval as module1 4 | 5 | sample_IDs_path = "evaluation/sample_IDs.csv" 6 | benchmark_dump_path = "evaluation/benchmark_dump/sample_items.json" 7 | 8 | def get_sample_qids(): 9 | sample_IDs = pd.read_csv(sample_IDs_path,sep=';') 10 | QIDs = list(sample_IDs['QID']) 11 | return QIDs 12 | 13 | def save_benchmark_dump(): 14 | errors = [] 15 | QIDs = get_sample_qids() 16 | sample_items = {} 17 | for QID in QIDs: 18 | print(QID) 19 | item = module1.get_Wikidata_item(QID) 20 | sample_items[QID] = item 21 | with open(benchmark_dump_path,'w') as f: 22 | json.dump(sample_items,f) 23 | print(errors) 24 | return 0 25 | 26 | def load_benchmark_dump(): 27 | with open(benchmark_dump_path,'r') as f: 28 | sample_items = json.load(f) 29 | return sample_items 30 | 31 | #save_benchmark_dump() 32 | #load_benchmark_dump() 33 | 34 | #print() -------------------------------------------------------------------------------- /evaluation/sample_IDs.csv: -------------------------------------------------------------------------------- 1 | GoldID;QID 2 | 310;Q11376 3 | 311;Q186300 4 | 312;Q834020 5 | 313;Q161254 6 | 314;Q161635 7 | 315;Q2945123 8 | 316;Q2248131 9 | 317;Q172881 10 | 318;Q843905 11 | 319;Q11382 12 | 320;Q2305665 13 | 321;Q1127660 14 | 322;Q272621 15 | 323;Q16853908 16 | 324;Q891408 17 | 325;Q849919 18 | 326;Q103438301 19 | 327;Q3502299 20 | 328;Q166530 21 | 329;Q875744 22 | 330;Q11402 23 | 331;Q1068463 24 | 332;Q1322540 25 | 333;Q140028 26 | 334;Q11652 27 | 335;Q82580 28 | 336;Q219207 29 | 337;Q6806305 30 | 338;Q30006 31 | 339;Q11412 32 | 340;Q1544012 33 | 341;Q660488 34 | 342;Q1060137 35 | 343;Q170282 36 | 344;Q497332 37 | 345;Q46276 38 | 346;Q103687426 39 | 347;Q599404 40 | 348;Q172137 41 | 349;Q217255 42 | 350;Q35875 43 | 351;Q6421317 44 | 352;Q165618 45 | 353;Q41273 46 | 354;Q2397319 47 | 355;Q3235565 48 | 356;Q170475 49 | 357;Q20702 50 | 358;Q25342 51 | 359;Q240105 52 | 360;Q11663629 53 | 361;Q96941619 54 | 362;Q676622 55 | 363;Q3711325 56 | 364;Q2111 57 | 365;Q12507 58 | 366;Q3299367 59 | 367;Q824561 60 | 368;Q206175 61 | 369;Q2673034 62 | 370;Q103715245 63 | 371;Q48103 64 | 372;Q376742 65 | 373;Q11465 66 | 374;Q192510 67 | 375;Q42213 68 | -------------------------------------------------------------------------------- /evaluation/module_workflow.txt: -------------------------------------------------------------------------------- 1 | Instructor input 2 | Formula question QID: 'Q11376' 3 | System output: 'Generating physics formula question for >>acceleration<<...' 4 | 5 | Module 0: Formula and Identifier Retrieval 6 | 'defining formula' (P2534) 7 | -> 'a = dv/dt' 8 | a: 'acceleration' (Q11376) 9 | v: 'velocity' (Q11465) 10 | t: 'duration' (Q2199864) 11 | 12 | Module 1: Identifier unit retrieval 13 | 'ISQ dimension' property (P4020) 14 | -> '\mathsf{L} \mathsf{T}^{-2}'' 15 | 16 | Module 2: Fomula rearrangement 17 | CAS formula rearrangements 18 | -> 19 | 'F = m a' 20 | 'm = F/a' 21 | 'a = F/m' 22 | 23 | Module 3: Identifier value generation 24 | {F,m,a} = {6,2,3}; {6,3,2}, ... 25 | (randomize) 26 | 27 | Module 4: Question text generation 28 | a) 'What is the force F given mass m = 2 kg and acceleration a = 3 m/s^2 ?' 29 | b) 'What is the mass m given force F = 6 N and acceleration a = 3 m/s^2 ?' 30 | c) 'What is the acceleration a given Force F = 6 N and mass m = 2 kg ?' 31 | (randomize) 32 | 33 | Student input 34 | a) 'Force F = 6 N' 35 | b) c) ... 36 | 37 | Module 5: Solution value and unit check 38 | check solution value 39 | 'correct' 40 | check solution unit 41 | 'correct' -------------------------------------------------------------------------------- /evaluation/module1_formula_and_identifier_retrieval/GoldID-QID_correspondence.csv: -------------------------------------------------------------------------------- 1 | GoldID; QID 2 | 310;Q11376 3 | 311;Q186300 4 | 312;Q834020 5 | 313;Q161254 6 | 314;Q161635 7 | 315;Q2945123 8 | 316;Q2248131 9 | 317;Q172881 10 | 318;Q843905 11 | 319;Q11382 12 | 320;Q2305665 13 | 321;Q1127660 14 | 322;Q272621 15 | 323;Q16853908 16 | 324;Q891408 17 | 325;Q849919 18 | 326;Q103438301 19 | 327;Q103439852 20 | 328;Q166530 21 | 329;Q875744 22 | 330;Q11402 23 | 331;Q1068463 24 | 332;Q1322540 25 | 333;Q140028 26 | 334;Q11652 27 | 335;Q82580 28 | 336;Q219207 29 | 337;Q6806305 30 | 338;Q30006 31 | 339;Q11412 32 | 340;Q1544012 33 | 341;Q660488 34 | 342;Q1060137 35 | 343;Q170282 36 | 344;Q497332 37 | 345;Q46276 38 | 346;Q103687426 39 | 347;Q599404 40 | 348;Q172137 41 | 349;Q217255 42 | 350;Q35875 43 | 351;Q6421317 44 | 352;Q165618 45 | 353;Q41273 46 | 354;Q2397319 47 | 355;Q3235565 48 | 356;Q170475 49 | 357;Q20702 50 | 358;Q25342 51 | 359;Q240105 52 | 360;Q11663629 53 | 361;Q96941619 54 | 362;Q676622 55 | 363;Q3711325 56 | 364;Q2111 57 | 365;Q12507 58 | 366;Q3299367 59 | 367;Q824561 60 | 368;Q206175 61 | 369;Q2822927 62 | 370;Q103715245 63 | 371;Q48103 64 | 372;Q376742 65 | 373;Q11465 66 | 374;Q192510 67 | 375;Q42213 68 | -------------------------------------------------------------------------------- /module6_explanation_text_generation.py: -------------------------------------------------------------------------------- 1 | def generate_explanation_text(concept_qid,defining_formula, 2 | identifier_properties,identifier_values,): 3 | 4 | #url = "https://www.wikidata.org/wiki/" + concept_qid 5 | url = "www.wikidata.org/wiki/" + concept_qid 6 | # insert values 7 | 8 | symbol_value_unit = {} 9 | try: 10 | for idx in range(len(identifier_properties)): 11 | symbol_value_unit[identifier_properties[idx][1]] = " " + str(identifier_values[idx]) + " " + identifier_properties[idx][2] + " " 12 | 13 | values_inserted = "" 14 | for character in defining_formula: 15 | try: 16 | character = character.replace(character,symbol_value_unit[character]) 17 | except: 18 | pass 19 | values_inserted += character 20 | 21 | explanation_text = "Solution from " + url + " formula " + defining_formula + " with " + values_inserted + "." 22 | 23 | except: 24 | try: 25 | explanation_text = "Solution from " + url + " formula " + defining_formula + " ." 26 | except: 27 | explanation_text = "" 28 | 29 | return explanation_text -------------------------------------------------------------------------------- /module_unit_tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from old import module0_formula_and_identifier_retrieval 4 | 5 | import pandas as pd 6 | 7 | # Python Tutorial: Unit Testing Your Code with the unittest Module: 8 | #https://www.youtube.com/watch?v=6tNS--WetLI 9 | 10 | # Retrieve sample QIDs 11 | sample_IDs_filepath = r'evaluation\sample_IDs.csv' 12 | QIDs_column_name = 'QID' 13 | 14 | def get_sample_QIDs(): 15 | sample_IDs_table = pd.read_csv(sample_IDs_filepath,delimiter=';') 16 | sample_QIDs = list(sample_IDs_table[QIDs_column_name]) 17 | return sample_QIDs 18 | 19 | class TestModules(unittest.TestCase): 20 | 21 | # TEST MODULE0 22 | def test_module0(self): 23 | #qid = 'Q11376' 24 | #sample_QIDs = [qid] 25 | sample_QIDs = get_sample_QIDs() 26 | for qid in sample_QIDs: 27 | Wikidata_item = module0_formula_and_identifier_retrieval \ 28 | .get_Wikidata_item(qid) 29 | 30 | self.assertIsNotNone(Wikidata_item) 31 | #self.assertIsNotNone(module0_formula_and_identifier_retrieval 32 | # .get_concept_name(Wikidata_item)) 33 | 34 | # TEST MODULE1 35 | def test_module1(self): 36 | # TODO: insert code for unit test of module1 here 37 | pass 38 | 39 | if __name__ == '__main__': 40 | unittest.main() -------------------------------------------------------------------------------- /login/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 |

Login

6 |
7 | {% with messages = get_flashed_messages() %} 8 | {% if messages %} 9 |
10 | {{ messages[0] }} 11 |
12 | {% endif %} 13 | {% endwith %} 14 |
15 |
16 |
17 | 18 |
19 |
20 | 21 |
22 |
23 | 24 |
25 |
26 |
27 | 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} -------------------------------------------------------------------------------- /login/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 |

Sign Up

6 |
7 | {% with messages = get_flashed_messages() %} 8 | {% if messages %} 9 |
10 | {{ messages[0] }}
Go to login page. 11 |
12 | {% endif %} 13 | {% endwith %} 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 |
38 | {% endblock %} -------------------------------------------------------------------------------- /module4_question_text_generation.py: -------------------------------------------------------------------------------- 1 | def get_question_text(formula_identifiers,identifier_values): 2 | """Get question text from identifier names, symbols, and units.""" 3 | 4 | # Get identifier information (name,symbol,value,unit) 5 | identifier_information = [] 6 | 7 | for identifier_index in range(len(formula_identifiers)): 8 | identifier_name = formula_identifiers[identifier_index][1] 9 | identifier_symbol = formula_identifiers[identifier_index][0] 10 | identifier_unit = formula_identifiers[identifier_index][2] 11 | identifier_value = str(identifier_values[identifier_index]) 12 | identifier_information.append((identifier_name,identifier_symbol,identifier_value,identifier_unit)) 13 | 14 | # Generate question text 15 | 16 | # Left-hand side identifiers 17 | left_hand_side_identifier = identifier_information[0] 18 | question_text = 'What is the ' 19 | question_text += ' '.join([left_hand_side_identifier[1],left_hand_side_identifier[0]]) + ', given ' 20 | 21 | # Right-hand side identifiers 22 | right_hand_side_identifiers = identifier_information[1:] 23 | for right_hand_side_identifier in right_hand_side_identifiers: 24 | question_text += right_hand_side_identifier[1] + ' ' + right_hand_side_identifier[0] + ' = ' + str(right_hand_side_identifier[2]) + ' ' + right_hand_side_identifier[3] + ', ' 25 | 26 | # Finalize 27 | question_text = question_text[:-2] + ' ?' 28 | 29 | return question_text -------------------------------------------------------------------------------- /evaluation/module1_formula_and_identifier_retrieval/unit_test_module.csv: -------------------------------------------------------------------------------- 1 | GoldID; QID;Concept name correct;Defining formula correct;Formula Identifiers correct;Issue;Code line 2 | 310;Q11376;;;;; 3 | 311;Q186300;;;;; 4 | 312;Q834020;;;;; 5 | 313;Q161254;;;;; 6 | 314;Q161635;;;;; 7 | 315;Q2945123;;;;; 8 | 316;Q2248131;;;;; 9 | 317;Q172881;;;;; 10 | 318;Q843905;;;;; 11 | 319;Q11382;;;;; 12 | 320;Q2305665;;;;; 13 | 321;Q1127660;;;;; 14 | 322;Q272621;;;;; 15 | 323;Q16853908;;;;; 16 | 324;Q891408;;;;; 17 | 325;Q849919;;;;; 18 | 326;Q103438301;;;;; 19 | 327;Q103439852;;;;; 20 | 328;Q166530;;;;; 21 | 329;Q875744;;;;; 22 | 330;Q11402;;;;; 23 | 331;Q1068463;;;;; 24 | 332;Q1322540;;;;; 25 | 333;Q140028;;;;; 26 | 334;Q11652;;;;; 27 | 335;Q82580;;;;; 28 | 336;Q219207;;;;; 29 | 337;Q6806305;;;;; 30 | 338;Q30006;;;;; 31 | 339;Q11412;;;;; 32 | 340;Q1544012;;;;; 33 | 341;Q660488;;;;; 34 | 342;Q1060137;;;;; 35 | 343;Q170282;;;;; 36 | 344;Q497332;;;;; 37 | 345;Q46276;;;;; 38 | 346;Q103687426;;;;; 39 | 347;Q599404;;;;; 40 | 348;Q172137;;;;; 41 | 349;Q217255;;;;; 42 | 350;Q35875;;;;; 43 | 351;Q6421317;;;;; 44 | 352;Q165618;;;;; 45 | 353;Q41273;;;;; 46 | 354;Q2397319;;;;; 47 | 355;Q3235565;;;;; 48 | 356;Q170475;;;;; 49 | 357;Q20702;;;;; 50 | 358;Q25342;;;;; 51 | 359;Q240105;;;;; 52 | 360;Q11663629;;;;; 53 | 361;Q96941619;;;;; 54 | 362;Q676622;;;;; 55 | 363;Q3711325;;;;; 56 | 364;Q2111;;;;; 57 | 365;Q12507;;;;; 58 | 366;Q3299367;;;;; 59 | 367;Q824561;;;;; 60 | 368;Q206175;;;;; 61 | 369;Q2822927;;;;; 62 | 370;Q103715245;;;;; 63 | 371;Q48103;;;;; 64 | 372;Q376742;;;;; 65 | 373;Q11465;;;;; 66 | 374;Q192510;;;;; 67 | 375;Q42213;;;;; 68 | -------------------------------------------------------------------------------- /evaluation/module_workflow/unit_test_module_workflow_empty.csv: -------------------------------------------------------------------------------- 1 | GoldID;QID;Name;Working;Formula;Identifiers;Properties;Formula unit;Identifier units;Formula sympy;Identifiers sympy;Sympy rhs 2 | 310;Q11376;;;;;;;;;; 3 | 311;Q186300;;;;;;;;;; 4 | 312;Q834020;;;;;;;;;; 5 | 313;Q161254;;;;;;;;;; 6 | 314;Q161635;;;;;;;;;; 7 | 315;Q2945123;;;;;;;;;; 8 | 316;Q2248131;;;;;;;;;; 9 | 317;Q172881;;;;;;;;;; 10 | 318;Q843905;;;;;;;;;; 11 | 319;Q11382;;;;;;;;;; 12 | 320;Q2305665;;;;;;;;;; 13 | 321;Q1127660;;;;;;;;;; 14 | 322;Q272621;;;;;;;;;; 15 | 323;Q16853908;;;;;;;;;; 16 | 324;Q891408;;;;;;;;;; 17 | 325;Q849919;;;;;;;;;; 18 | 326;Q103438301;;;;;;;;;; 19 | 327;Q103439852;;;;;;;;;; 20 | 328;Q166530;;;;;;;;;; 21 | 329;Q875744;;;;;;;;;; 22 | 330;Q11402;;;;;;;;;; 23 | 331;Q1068463;;;;;;;;;; 24 | 332;Q1322540;;;;;;;;;; 25 | 333;Q140028;;;;;;;;;; 26 | 334;Q11652;;;;;;;;;; 27 | 335;Q82580;;;;;;;;;; 28 | 336;Q219207;;;;;;;;;; 29 | 337;Q6806305;;;;;;;;;; 30 | 338;Q30006;;;;;;;;;; 31 | 339;Q11412;;;;;;;;;; 32 | 340;Q1544012;;;;;;;;;; 33 | 341;Q660488;;;;;;;;;; 34 | 342;Q1060137;;;;;;;;;; 35 | 343;Q170282;;;;;;;;;; 36 | 344;Q497332;;;;;;;;;; 37 | 345;Q46276;;;;;;;;;; 38 | 346;Q103687426;;;;;;;;;; 39 | 347;Q599404;;;;;;;;;; 40 | 348;Q172137;;;;;;;;;; 41 | 349;Q217255;;;;;;;;;; 42 | 350;Q35875;;;;;;;;;; 43 | 351;Q6421317;;;;;;;;;; 44 | 352;Q165618;;;;;;;;;; 45 | 353;Q41273;;;;;;;;;; 46 | 354;Q2397319;;;;;;;;;; 47 | 355;Q3235565;;;;;;;;;; 48 | 356;Q170475;;;;;;;;;; 49 | 357;Q20702;;;;;;;;;; 50 | 358;Q25342;;;;;;;;;; 51 | 359;Q240105;;;;;;;;;; 52 | 360;Q11663629;;;;;;;;;; 53 | 361;Q96941619;;;;;;;;;; 54 | 362;Q676622;;;;;;;;;; 55 | 363;Q3711325;;;;;;;;;; 56 | 364;Q2111;;;;;;;;;; 57 | 365;Q12507;;;;;;;;;; 58 | 366;Q3299367;;;;;;;;;; 59 | 367;Q824561;;;;;;;;;; 60 | 368;Q206175;;;;;;;;;; 61 | 369;Q2822927;;;;;;;;;; 62 | 370;Q103715245;;;;;;;;;; 63 | 371;Q48103;;;;;;;;;; 64 | 372;Q376742;;;;;;;;;; 65 | 373;Q11465;;;;;;;;;; 66 | 374;Q192510;;;;;;;;;; 67 | 375;Q42213;;;;;;;;;; 68 | -------------------------------------------------------------------------------- /login/__init__.py: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | ################# Importing packages ####################### 3 | ######################################################################## 4 | from flask import Flask 5 | from flask_sqlalchemy import SQLAlchemy 6 | from flask_login import LoginManager 7 | 8 | 9 | # init SQLAlchemy so we can use it later in our models 10 | db = SQLAlchemy() 11 | def create_app(): 12 | app = Flask(__name__) # creates the Flask instance, __name__ is the name of the current Python module 13 | app.config['SECRET_KEY'] = 'secret-key-goes-here' # it is used by Flask and extensions to keep data safe 14 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite' #it is the path where the SQLite database file will be saved 15 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # deactivate Flask-SQLAlchemy track modifications 16 | db.init_app(app) # Initialiaze sqlite database 17 | # The login manager contains the code that lets your application and Flask-Login work together 18 | login_manager = LoginManager() # Create a Login Manager instance 19 | login_manager.login_view = 'auth.login' # define the redirection path when login required and we attempt to access without being logged in 20 | login_manager.init_app(app) # configure it for login 21 | from models import User 22 | @login_manager.user_loader 23 | def load_user(user_id): #reload user object from the user ID stored in the session 24 | # since the user_id is just the primary key of our user table, use it in the query for the user 25 | return User.query.get(int(user_id)) 26 | # blueprint for auth routes in our app 27 | # blueprint allow you to orgnize your flask app 28 | from auth import auth as auth_blueprint 29 | app.register_blueprint(auth_blueprint) 30 | # blueprint for non-auth parts of app 31 | from main import main as main_blueprint 32 | app.register_blueprint(main_blueprint) 33 | return app -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | # This workflow uses actions that are not certified by GitHub. 4 | # They are provided by a third-party and are governed by 5 | # separate terms of service, privacy policy, and support 6 | # documentation. 7 | 8 | on: 9 | schedule: 10 | - cron: '31 2 * * *' 11 | push: 12 | branches: [ main ] 13 | # Publish semver tags as releases. 14 | tags: [ 'v*.*.*' ] 15 | pull_request: 16 | branches: [ main ] 17 | 18 | env: 19 | # Use docker.io for Docker Hub if empty 20 | REGISTRY: ghcr.io 21 | # github.repository as / 22 | IMAGE_NAME: ${{ github.repository }} 23 | 24 | 25 | jobs: 26 | build: 27 | 28 | runs-on: ubuntu-latest 29 | permissions: 30 | contents: read 31 | packages: write 32 | 33 | steps: 34 | - name: Checkout repository 35 | uses: actions/checkout@v2 36 | 37 | # Login against a Docker registry except on PR 38 | # https://github.com/docker/login-action 39 | - name: Log into registry ${{ env.REGISTRY }} 40 | if: github.event_name != 'pull_request' 41 | uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c 42 | with: 43 | registry: ${{ env.REGISTRY }} 44 | username: ${{ github.actor }} 45 | password: ${{ secrets.GITHUB_TOKEN }} 46 | 47 | # Extract metadata (tags, labels) for Docker 48 | # https://github.com/docker/metadata-action 49 | - name: Extract Docker metadata 50 | id: meta 51 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 52 | with: 53 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 54 | 55 | # Build and push Docker image with Buildx (don't push on PR) 56 | # https://github.com/docker/build-push-action 57 | - name: Build and push Docker image 58 | uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc 59 | with: 60 | context: . 61 | push: ${{ github.event_name != 'pull_request' }} 62 | tags: ${{ steps.meta.outputs.tags }} 63 | labels: ${{ steps.meta.outputs.labels }} 64 | -------------------------------------------------------------------------------- /login/templates/teacher.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PhysWikiQuiz 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | Examples 33 | Dataset 34 | Demovideo 35 | 36 | 37 | GitHub 38 | 39 |
40 | 41 |

PhysWikiQuiz

42 |

Physics Exam Question Generation and Test System

43 | Teacher 44 | Student 45 | 46 |
Enter Formula Concept Name or QID (e.g., 'speed' or 'Q11376'):
47 | 48 |
49 | 50 | 51 |
52 | 53 |
Formula Concept Question:
54 | 55 |
56 | 57 |
58 | 59 |
60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /module2_formula_rearrangement.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import sympy 3 | import random 4 | 5 | def get_random_formula_rearrangements(defining_formula,formula_identifiers): 6 | """Generate random formula rearrangements using Sympy.""" 7 | 8 | formula_rearrangements = [] 9 | try: 10 | # Transform LaTeX to Sympy 11 | url = "https://vmext-demo.formulasearchengine.com/math/translation" 12 | params = {'cas': 'SymPy', 'genericExperimentalFeatures': 'true', 'latex': defining_formula} 13 | response = requests.post(url, params=params) 14 | formula_string = response.json()['result'] 15 | # translate formula lhs and rhs 16 | formula_lhs_sympy = sympy.sympify(formula_string.split("==")[0]) 17 | formula_rhs_sympy = sympy.sympify(formula_string.split("==")[1]) 18 | # translate identifiers 19 | identifiers_sympy = sympy.symbols(' '.join([identifier[1] for identifier in formula_identifiers])) 20 | 21 | # Solve equation for different identifiers 22 | for identifier in identifiers_sympy: 23 | eq = sympy.Eq(lhs=formula_lhs_sympy,rhs=formula_rhs_sympy) 24 | formula_rearrangements.append((identifier,sympy.solve(eq,identifier))) 25 | 26 | # select random rearrangement 27 | selected = random.choice(formula_rearrangements) 28 | # update defining formula 29 | defining_formula_rearranged = str(selected[0]) + " = " + str(selected[1][0]) 30 | # rearrange identifier 31 | lhs_identifier = [] 32 | rhs_identifier = [] 33 | for identifier in formula_identifiers: 34 | if identifier[1] == str(selected[0]): 35 | lhs_identifier.append(identifier) 36 | formula_unit_dimension = identifier[2] 37 | else: 38 | rhs_identifier.append(identifier) 39 | formula_identifiers_rearranged = lhs_identifier + rhs_identifier 40 | 41 | except: 42 | # if formula rearrangement was not successful 43 | defining_formula_rearranged = defining_formula 44 | formula_identifiers_rearranged = formula_identifiers 45 | formula_unit_dimension = formula_identifiers[0][2] 46 | 47 | return defining_formula_rearranged,formula_identifiers_rearranged,formula_unit_dimension -------------------------------------------------------------------------------- /login/templates/student.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PhysWikiQuiz 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | Examples 33 | Dataset 34 | Demovideo 35 | 36 | 37 | GitHub 38 | 39 |
40 | 41 |

PhysWikiQuiz

42 |

Physics Exam Question Generation and Test System

43 | Teacher 44 | Student 45 | 46 |
Formula Concept Question:
47 | 48 |
49 | 50 |
51 | 52 |
Enter Formula Concept Question Answer:
53 | 54 |
55 | 56 | 57 |
58 |
59 |
60 | 61 |

62 | 63 |
64 | 65 |
66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #666; 3 | font-family: Helvetica,Arial,sans-serif; 4 | } 5 | h1 { 6 | text-align: center; 7 | } 8 | .glyphicon-refresh-animate { 9 | -animation: spin .7s infinite linear; 10 | -webkit-animation: spin2 .7s infinite linear; 11 | } 12 | 13 | @-webkit-keyframes spin2 { 14 | from { -webkit-transform: rotate(0deg);} 15 | to { -webkit-transform: rotate(360deg);} 16 | } 17 | 18 | @keyframes spin { 19 | from { transform: scale(1) rotate(0deg);} 20 | to { transform: scale(1) rotate(360deg);} 21 | } 22 | 23 | #main { 24 | margin: 70px auto 0px; 25 | padding: 20px; 26 | width:800px; 27 | min-height:700px; 28 | background:#eee; 29 | border:1px solid; 30 | border-color:#e5e5e5 #dbdbdb #d2d2d2; 31 | -webkit-box-shadow:rgba(0,0,0,0.3) 0 1px 3px; 32 | -moz-box-shadow:rgba(0,0,0,0.3) 0 1px 3px; 33 | box-shadow:rgba(0,0,0,0.3) 0 1px 3px; 34 | } 35 | #question-form { 36 | width: 700px; 37 | margin: 0px auto; 38 | position: relative; 39 | } 40 | #question { 41 | display: block; 42 | width: 680px; 43 | margin: 0px auto; 44 | padding: 10px; 45 | font-size: 1.5em; 46 | border:none; 47 | } 48 | 49 | #submit { 50 | background: none; 51 | border: none; 52 | position: absolute; 53 | right: 0; 54 | top: 0; 55 | cursor: pointer; 56 | padding: 10px; 57 | } 58 | #result { 59 | margin: 15px 0px; 60 | } 61 | #footer { 62 | border-top: 1px solid #dbdbdb; 63 | font-size: small; 64 | } 65 | #language-selector { 66 | float: right; 67 | } 68 | #legal { 69 | margin: 25px auto; 70 | width: 800px; 71 | font-size: small; 72 | } 73 | #legal img { 74 | vertical-align: middle; 75 | } 76 | .error { 77 | color: red; 78 | } 79 | .inner { 80 | padding: 10px; 81 | } 82 | .simplemodal-container { 83 | background-color: white; 84 | border: 2px solid; 85 | border-color: #e5e5e5 #dbdbdb #d2d2d2; 86 | } 87 | .dialog-header { 88 | padding: 10px; 89 | margin: 5px 0px 0px; 90 | border-bottom: 7px solid #dbdbdb; 91 | } 92 | .close { 93 | float: right; 94 | } 95 | .entity-select { 96 | margin: 0; 97 | cursor: pointer; 98 | padding: 10px; 99 | border-bottom: 1px solid #dbdbdb; 100 | } 101 | .entity-select:hover { 102 | background-color: #4c59a6; 103 | color: white; 104 | } 105 | .label { 106 | font-weight: bold; 107 | } 108 | .aliases { 109 | font-style: italic; 110 | } 111 | -------------------------------------------------------------------------------- /login/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #666; 3 | font-family: Helvetica,Arial,sans-serif; 4 | } 5 | h1 { 6 | text-align: center; 7 | } 8 | .glyphicon-refresh-animate { 9 | -animation: spin .7s infinite linear; 10 | -webkit-animation: spin2 .7s infinite linear; 11 | } 12 | 13 | @-webkit-keyframes spin2 { 14 | from { -webkit-transform: rotate(0deg);} 15 | to { -webkit-transform: rotate(360deg);} 16 | } 17 | 18 | @keyframes spin { 19 | from { transform: scale(1) rotate(0deg);} 20 | to { transform: scale(1) rotate(360deg);} 21 | } 22 | 23 | #main { 24 | margin: 70px auto 0px; 25 | padding: 20px; 26 | width:800px; 27 | min-height:700px; 28 | background:#eee; 29 | border:1px solid; 30 | border-color:#e5e5e5 #dbdbdb #d2d2d2; 31 | -webkit-box-shadow:rgba(0,0,0,0.3) 0 1px 3px; 32 | -moz-box-shadow:rgba(0,0,0,0.3) 0 1px 3px; 33 | box-shadow:rgba(0,0,0,0.3) 0 1px 3px; 34 | } 35 | #question-form { 36 | width: 700px; 37 | margin: 0px auto; 38 | position: relative; 39 | } 40 | #question { 41 | display: block; 42 | width: 680px; 43 | margin: 0px auto; 44 | padding: 10px; 45 | font-size: 1.5em; 46 | border:none; 47 | } 48 | 49 | #submit { 50 | background: none; 51 | border: none; 52 | position: absolute; 53 | right: 0; 54 | top: 0; 55 | cursor: pointer; 56 | padding: 10px; 57 | } 58 | #result { 59 | margin: 15px 0px; 60 | } 61 | #footer { 62 | border-top: 1px solid #dbdbdb; 63 | font-size: small; 64 | } 65 | #language-selector { 66 | float: right; 67 | } 68 | #legal { 69 | margin: 25px auto; 70 | width: 800px; 71 | font-size: small; 72 | } 73 | #legal img { 74 | vertical-align: middle; 75 | } 76 | .error { 77 | color: red; 78 | } 79 | .inner { 80 | padding: 10px; 81 | } 82 | .simplemodal-container { 83 | background-color: white; 84 | border: 2px solid; 85 | border-color: #e5e5e5 #dbdbdb #d2d2d2; 86 | } 87 | .dialog-header { 88 | padding: 10px; 89 | margin: 5px 0px 0px; 90 | border-bottom: 7px solid #dbdbdb; 91 | } 92 | .close { 93 | float: right; 94 | } 95 | .entity-select { 96 | margin: 0; 97 | cursor: pointer; 98 | padding: 10px; 99 | border-bottom: 1px solid #dbdbdb; 100 | } 101 | .entity-select:hover { 102 | background-color: #4c59a6; 103 | color: white; 104 | } 105 | .label { 106 | font-weight: bold; 107 | } 108 | .aliases { 109 | font-style: italic; 110 | } 111 | -------------------------------------------------------------------------------- /templates/student.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PhysWikiQuiz 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | Examples 33 | Dataset 34 | Demovideo 35 | 36 | 37 | Manual 38 | Code 39 | API 40 | Publication 41 | 42 |
43 | 44 |

PhysWikiQuiz

45 |

Physics Exam Question Generation and Test System

46 | Teacher 47 | Student 48 | 49 |
Formula Concept Question:
50 | 51 |
52 | 53 |
54 | 55 |
Enter Answer:
56 | 57 |
58 | 59 | 60 |
61 |
62 |
63 | 64 |

65 | 66 |
67 | 68 |
69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /login/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | PhysWikiQuiz 13 | 14 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
32 | 62 |
63 | 64 |
65 |
66 | {% block content %}{% endblock %} 67 |
68 |
69 |
70 | 71 | 72 | -------------------------------------------------------------------------------- /evaluation/module_workflow/unit_test_module_workflow_manual(0).csv: -------------------------------------------------------------------------------- 1 | GoldID; QID;Name;Working (yes,no,part);Identifier (hp, cf, idf);Unit formula;Units identifier;Formula sympy;Identifier sympy;Sympy rhs;Issue;Module;Code line;Error output;Comment 2 | 310;Q11376;acceleration;part;idf;yes;yes;Derivative(v, t);(a, v, t);Subs(Derivative(4, t), t, 8);it says value incorrect even though it is correct;3;;; 3 | 311;Q186300;angular acceleration;no;idf;yes;yes;N/A;(\boldsymbol{\alpha}, \boldsymbol{\omega}, t);N/A;substitution of Greek letters in \boldsymbol{\};3;;; 4 | 312;Q834020;angular frequency;yes;idf;yes;yes;2*pi*f;(\omega, f);16*pi;;;;; 5 | 313;Q161254;angular momentum;part;idf;yes;yes;R*p;(L, r, p);2*R;;3;;; 6 | 314;Q161635;angular velocity;no;idf;yes;yes;N/A;N/A;N/A;substitution of Greek letters in \boldsymbol{\};3;;; 7 | 315;Q2945123;center of mass;no;cf;no;no;N/A;N/A;N/A;;;;; 8 | 316;Q2248131;centripetal acceleration;no;cf, idf;yes;yes;N/A;(v, r, a_c);N/A;index a_c;3;;; 9 | 317;Q172881;centripetal force;no;hp;yes;yes;N/A;(F, m, v, r);N/A;;;;; 10 | 318;Q843905;;;;;;;;;;;;; 11 | 319;Q11382;;;;;;;;;;;;; 12 | 320;Q2305665;;;;;;;;;;;;; 13 | 321;Q1127660;;;;;;;;;;;;; 14 | 322;Q272621;;no;;;;;;;;;;; 15 | 323;Q16853908;;;;;;;;;;;;; 16 | 324;Q891408;;;;;;;;;;;;; 17 | 325;Q849919;;;;;;;;;;;;; 18 | 326;Q103438301;;;;;;;;;;;;; 19 | 327;Q103439852;;;;;;;;;;;;; 20 | 328;Q166530;;;;;;;;;;;;; 21 | 329;Q875744;;;;;;;;;;;;; 22 | 330;Q11402;;;;;;;;;;;;; 23 | 331;Q1068463;;;;;;;;;;;;; 24 | 332;Q1322540;;;;;;;;;;;;; 25 | 333;Q140028;;;;;;;;;;;;; 26 | 334;Q11652;;;;;;;;;;;;; 27 | 335;Q82580;;;;;;;;;;;;; 28 | 336;Q219207;;;;;;;;;;;;; 29 | 337;Q6806305;;;;;;;;;;;;; 30 | 338;Q30006;;;;;;;;;;;;; 31 | 339;Q11412;;;;;;;;;;;;; 32 | 340;Q1544012;;;;;;;;;;;;; 33 | 341;Q660488;;;;;;;;;;;;; 34 | 342;Q1060137;;;;;;;;;;;;; 35 | 343;Q170282;;;;;;;;;;;;; 36 | 344;Q497332;;;;;;;;;;;;; 37 | 345;Q46276;;;;;;;;;;;;; 38 | 346;Q103687426;;;;;;;;;;;;; 39 | 347;Q599404;;;;;;;;;;;;; 40 | 348;Q172137;;;;;;;;;;;;; 41 | 349;Q217255;;;;;;;;;;;;; 42 | 350;Q35875;;;;;;;;;;;;; 43 | 351;Q6421317;;;;;;;;;;;;; 44 | 352;Q165618;;;;;;;;;;;;; 45 | 353;Q41273;;;;;;;;;;;;; 46 | 354;Q2397319;;;;;;;;;;;;; 47 | 355;Q3235565;;;;;;;;;;;;; 48 | 356;Q170475;;;;;;;;;;;;; 49 | 357;Q20702;;;;;;;;;;;;; 50 | 358;Q25342;;;;;;;;;;;;; 51 | 359;Q240105;;;;;;;;;;;;; 52 | 360;Q11663629;;;;;;;;;;;;; 53 | 361;Q96941619;;;;;;;;;;;;; 54 | 362;Q676622;;;;;;;;;;;;; 55 | 363;Q3711325;;;;;;;;;;;;; 56 | 364;Q2111;;;;;;;;;;;;; 57 | 365;Q12507;;;;;;;;;;;;; 58 | 366;Q3299367;;;;;;;;;;;;; 59 | 367;Q824561;;;;;;;;;;;;; 60 | 368;Q206175;;;;;;;;;;;;; 61 | 369;Q2822927;;;;;;;;;;;;; 62 | 370;Q103715245;;;;;;;;;;;;; 63 | 371;Q48103;;;;;;;;;;;;; 64 | 372;Q376742;;;;;;;;;;;;; 65 | 373;Q11465;;;;;;;;;;;;; 66 | 374;Q192510;;;;;;;;;;;;; 67 | 375;Q42213;;;;;;;;;;;;; 68 | -------------------------------------------------------------------------------- /evaluation/module1_formula_and_identifier_retrieval/Identifier_Unit_Wikidata_Properties_evaluator.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import requests 3 | 4 | # INIT 5 | 6 | # set paths 7 | evaluation_path = "Identifier_Unit_Wikidata_Properties_evaluation.csv" 8 | correspondence_path = "GoldID-QID_correspondence.csv" 9 | 10 | # open csv tables 11 | evaluation_table = pd.read_csv(evaluation_path,delimiter=";") 12 | correspondence_table = pd.read_csv(correspondence_path,delimiter=";") 13 | new_evaluation_table = evaluation_table 14 | 15 | # DEFINE 16 | 17 | def get_qid(goldid): 18 | """Map GoldID to QID.""" 19 | 20 | # https://stackoverflow.com/questions/61964973/pandas-get-column-value-where-row-matches-condition 21 | # https://www.interviewqs.com/ddi-code-snippets/rows-cols-python 22 | # https://www.geeksforgeeks.org/select-rows-columns-by-name-or-index-in-pandas-dataframe-using-loc-iloc/ 23 | 24 | condition = correspondence_table['GoldID'] == goldid 25 | row = correspondence_table[condition] 26 | qid = row.values[0][1] 27 | return qid 28 | 29 | # test 'get_qid' function 30 | # qid = get_qid(320) 31 | 32 | def write_formula_qid(row): 33 | """Write QID in 'Formula QID' column.""" 34 | 35 | goldid = row[1]['GoldID'] 36 | qid = get_qid(goldid) 37 | print(qid) 38 | 39 | #TODO: 40 | # write ... 41 | # ... 42 | 43 | def get_wikidata_item(qid): 44 | """Return Wikidata item data for QID.""" 45 | # https://www.wikidata.org/wiki/Special:EntityData/QID.json 46 | item = requests.get("https://wikidata.org/entity/" + qid) 47 | return item.json()['entities'][qid] 48 | 49 | # test 'get_wikidata_item' function 50 | # item = get_wikidata_item("Q11376") 51 | 52 | def write_unit_info_Wikidata(row): 53 | """Write unit infos in respective columns.""" 54 | 55 | qid = row[1]['Identifier QID'] 56 | item = get_wikidata_item(qid) 57 | claims = item['claims'] 58 | 59 | def get_value(claims,property): 60 | try: 61 | value = claims[property][0]['mainsnak']['datavalue']['value'] 62 | except: 63 | value = '' 64 | return value 65 | 66 | # get unit Wikidata infos 67 | isq_dim = get_value(claims,property='P4020') 68 | print(isq_dim) 69 | rec_unit_meas = get_value(claims,property='8111') 70 | print(rec_unit_meas) 71 | num_val = get_value(claims,property='P1181') 72 | print(num_val) 73 | 74 | #TODO: 75 | # write ... 76 | # ... 77 | 78 | # EXECUTE 79 | 80 | # iterate through table rows 81 | for row in evaluation_table.iterrows(): 82 | write_formula_qid(row) 83 | write_unit_info_Wikidata(row) 84 | 85 | pd.write_csv("Identifier_Unit_Wikidata_Properties_evaluation(filled).csv",delimiter=";") 86 | 87 | print("end") -------------------------------------------------------------------------------- /module3_identifier_value_generation.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import random 3 | import requests 4 | import urllib 5 | #import latex2sympy 6 | from latex2sympy2 import latex2sympy 7 | import sympy 8 | 9 | def get_sympy_from_latex_using_vmext_api(formula_latex): 10 | 11 | #Swagger UI 12 | # https://vmext-demo.formulasearchengine.com/swagger-ui.html 13 | 14 | #example: 15 | # https://vmext-demo.formulasearchengine.com/math/translation?cas=SymPy&genericExperimentalFeatures=true&latex=%5Cint_a%5Eb%20x%20dx 16 | # urllib.parse.quote(formula_latex) 17 | url = "https://vmext-demo.formulasearchengine.com/math/translation" 18 | params = {'cas': 'SymPy', 'genericExperimentalFeatures': 'true', 'latex': formula_latex} 19 | 20 | response = requests.post(url,params=params) 21 | formula_string = response.json()['result'] 22 | formula_sympy = sympy.sympify(formula_string.split("==")[1]) 23 | 24 | return formula_sympy 25 | 26 | def get_random_identifier_values(formula_identifiers,defining_formula): 27 | """Generate random identifier integer values.""" 28 | 29 | rhs_identifier_values = [] 30 | 31 | # define limit for right-hand side integer value 32 | lower_val_limit = 1 33 | upper_val_limit = 10 34 | 35 | # generate random integers for right-hand side identifiers 36 | for _ in itertools.repeat(None, len(formula_identifiers)-1): 37 | rhs_identifier_values.append(random.randint(lower_val_limit,upper_val_limit)) 38 | 39 | # generate resulting value for left-hand side identifier 40 | #defining_formula = 'x = y' 41 | # TODO: generalize 42 | identifiers_sympy = sympy.symbols(' '.join([identifier[1] for identifier in formula_identifiers])) 43 | #identifiers_sympy = sympy.symbols('a v t') 44 | print('Identifiers sympy: ',identifiers_sympy) 45 | 46 | # convert LaTeX to Sympy format 47 | # formula_sympy = latex2sympy.strToSympy(defining_formula) 48 | #formula_sympy = latex2sympy(defining_formula) 49 | formula_sympy = get_sympy_from_latex_using_vmext_api(defining_formula) 50 | print('Formula sympy: ',formula_sympy) 51 | 52 | # substitute generated random values to calculate left-hand side 53 | identifier_index = 0 54 | for identifier_sympy in identifiers_sympy: 55 | if identifier_index != 0:#lhs identifier 56 | formula_sympy = formula_sympy.subs(identifier_sympy,rhs_identifier_values[identifier_index-1]) 57 | identifier_index += 1 58 | try: 59 | lhs_identifier_value = formula_sympy.rhs 60 | except: 61 | lhs_identifier_value = formula_sympy 62 | print('Sympy rhs: ',lhs_identifier_value) 63 | 64 | identifier_values = [float(lhs_identifier_value)] 65 | identifier_values.extend(rhs_identifier_values) 66 | 67 | return identifier_values -------------------------------------------------------------------------------- /templates/teacher.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PhysWikiQuiz 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | Examples 33 | Dataset 34 | Demovideo 35 | 36 | 37 | Manual 38 | Code 39 | API 40 | Publication 41 | 42 |
43 | 44 |

PhysWikiQuiz

45 |

Physics Exam Question Generation and Test System

46 | Teacher 47 | Student 48 | 49 |
Enter Formula Concept Name or Wikidata QID (e.g., 'speed' or 'Q11376'):
50 | 51 |
52 | 53 | 54 |
55 | 56 |
Formula Concept Question:
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /templates/my-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PhysWikiQuiz 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | Examples 33 | Dataset 34 | Demovideo 35 | 36 | 37 | Manual 38 | Code 39 | API 40 | Publication 41 | 42 |
43 | 44 |

PhysWikiQuiz

45 |

Physics Exam Question Generation and Test System

46 | 47 |
Enter Formula Concept Name or Wikidata QID (e.g., 'speed' or 'Q11376'):
48 | 49 |
50 | 51 | 52 |
53 | 54 |
Formula Concept Question:
55 | 56 |
57 | 58 |
59 | 60 |
Enter Answer:
61 | 62 |
63 | 64 | 65 |
66 |
67 |
68 | 69 |

70 | 71 |
72 | 73 |
74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /templates/select.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PhysWikiQuiz 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | Examples 33 | Dataset 34 | Demovideo 35 | 36 | 37 | Manual 38 | Code 39 | API 40 | Publication 41 | 42 |
43 | 44 |

PhysWikiQuiz

45 |

Physics Exam Question Generation and Test System

46 | Teacher 47 | Student 48 | 49 |
Enter Formula Concept Name or Wikidata QID (e.g., 'speed' or 'Q11376'):
50 | 51 |
52 | 53 | 54 |
55 | 56 |
Formula Concept Question:
57 | 58 |
59 | 60 |
61 | 62 |
Enter Answer:
63 | 64 |
65 | 66 | 67 |
68 |
69 |
70 | 71 |

72 | 73 |
74 | 75 |
76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /old/module1_identifier_unit_retrieval.py: -------------------------------------------------------------------------------- 1 | from old.module0_formula_and_identifier_retrieval import get_Wikidata_item 2 | 3 | unit_property_key = 'P4020' 4 | 5 | def convert_unit_dimensions(ISQ_dimensions): 6 | """Convert unit from ISQ dimensions to SI units.""" 7 | 8 | unit_dimensions = ISQ_dimensions 9 | # Translate into SI standard form 10 | # mathsf_content = re.search(r'mathsf{(.*?)}', identifier_unit_dimension) 11 | for expression in ['\mathsf', '{', '}']: 12 | unit_dimensions = unit_dimensions.replace(expression, '') 13 | 14 | # Map Symbol for dimension to SI unit symbol 15 | # See https://en.wikipedia.org/wiki/International_System_of_Quantities 16 | mapping = {'L': 'm', 'M': 'kg', 'T': 's', 'I': 'A', '\Theta': 'K', 'N': 'mol', 'J': 'cd'} 17 | for k,v in mapping.items(): 18 | try: 19 | unit_dimensions = unit_dimensions.replace(k,v) 20 | except: 21 | pass 22 | SI_dimensions = unit_dimensions 23 | 24 | return SI_dimensions 25 | 26 | def get_formula_unit_dimension(Wikidata_item): 27 | """Get ISQ unit dimensions of formula.""" 28 | 29 | formula_unit_dimensions = Wikidata_item['claims'][unit_property_key][0]['mainsnak']['datavalue']['value'] 30 | # Convert from ISQ to SI 31 | formula_unit_dimensions = convert_unit_dimensions(formula_unit_dimensions) 32 | 33 | return formula_unit_dimensions 34 | 35 | def get_identifier_unit_dimensions(Wikidata_item): 36 | """Get ISQ unit dimensions of identifiers.""" 37 | 38 | identifier_unit_dimensions = [] 39 | 40 | # Retrieve right-hand side identifiers 41 | identifier_property_keys = ['P527', 'P4934'] # 'has part', 'calculated from' 42 | for property in identifier_property_keys: 43 | try: 44 | properties_object = Wikidata_item['claims'][property] 45 | except: 46 | pass 47 | 48 | for identifier_propery in properties_object: 49 | 50 | # get identifier unit 51 | identifier_item_qid = identifier_propery['mainsnak']['datavalue']['value']['id'] 52 | identifier_item = get_Wikidata_item(identifier_item_qid) 53 | identifier_unit_property = identifier_item['claims'][unit_property_key] 54 | identifier_unit_dimension = identifier_unit_property[0]['mainsnak']['datavalue']['value'] 55 | 56 | # Convert from ISQ to SI 57 | identifier_unit_dimension = convert_unit_dimensions(identifier_unit_dimension) 58 | 59 | identifier_unit_dimensions.append(identifier_unit_dimension) 60 | 61 | return identifier_unit_dimensions 62 | 63 | def update_identifiers_dict(formula_identifiers,formula_unit_dimension,identifier_unit_dimensions): 64 | """Update identifiers dict with units.""" 65 | 66 | updated_formula_identifiers = [] 67 | unit_dimensions = [formula_unit_dimension] 68 | unit_dimensions.extend(identifier_unit_dimensions) 69 | identifier_index = 0 70 | for identifier_tuple in formula_identifiers: 71 | identifier_triple = (identifier_tuple[0],identifier_tuple[1],unit_dimensions[identifier_index]) 72 | updated_formula_identifiers.append(identifier_triple) 73 | identifier_index += 1 74 | 75 | return updated_formula_identifiers -------------------------------------------------------------------------------- /login/auth.py: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | ###################### Import packages ################################### 3 | ######################################################################################## 4 | from flask import Blueprint, render_template, redirect, url_for, request, flash 5 | from werkzeug.security import generate_password_hash, check_password_hash 6 | from models import User 7 | from flask_login import login_user, logout_user, login_required, current_user 8 | from __init__ import db 9 | 10 | 11 | auth = Blueprint('auth', __name__) # create a Blueprint object that we name 'auth' 12 | 13 | @auth.route('/login', methods=['GET', 'POST']) # define login page path 14 | def login(): # define login page fucntion 15 | if request.method=='GET': # if the request is a GET we return the login page 16 | return render_template('login.html') 17 | else: # if the request is POST the we check if the user exist and with te right password 18 | email = request.form.get('email') 19 | password = request.form.get('password') 20 | remember = True if request.form.get('remember') else False 21 | user = User.query.filter_by(email=email).first() 22 | # check if the user actually exists 23 | # take the user-supplied password, hash it, and compare it to the hashed password in the database 24 | if not user: 25 | flash('Please sign up before!') 26 | return redirect(url_for('auth.signup')) 27 | elif not check_password_hash(user.password, password): 28 | flash('Please check your login details and try again.') 29 | return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page 30 | # if the above check passes, then we know the user has the right credentials 31 | login_user(user, remember=remember) 32 | return redirect(url_for('main.profile')) 33 | 34 | @auth.route('/signup', methods=['GET', 'POST'])# we define the sign up path 35 | def signup(): # define the sign up function 36 | if request.method=='GET': # If the request is GET we return the sign up page and forms 37 | return render_template('signup.html') 38 | else: # if the request is POST, then we check if the email doesn't already exist and then we save data 39 | email = request.form.get('email') 40 | name = request.form.get('name') 41 | password = request.form.get('password') 42 | user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database 43 | if user: # if a user is found, we want to redirect back to signup page so user can try again 44 | flash('Email address already exists') 45 | return redirect(url_for('auth.signup')) 46 | # create a new user with the form data. Hash the password so the plaintext version isn't saved. 47 | new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256')) # 48 | # add the new user to the database 49 | db.session.add(new_user) 50 | db.session.commit() 51 | return redirect(url_for('auth.login')) 52 | 53 | @auth.route('/logout') # define logout path 54 | @login_required 55 | def logout(): #define the logout function 56 | logout_user() 57 | return redirect(url_for('main.index')) -------------------------------------------------------------------------------- /evaluation/module_workflow/LaTeX2Sympy_vs._LaCASt.tgn: -------------------------------------------------------------------------------- 1 | {"rows_views":[[{"style":{"borders":"","font_style":{"bold":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{"bold":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{"font-weight":"normal","bold":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{"bold":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{"bold":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"","font_style":{"italic":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}],[{"style":{"borders":"","font_style":{"italic":true},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}},{"style":{"borders":"","font_style":{},"text_color":"","bg_color":"","halign":"left","valign":"top","padding":{"top":10,"right":5,"bottom":10,"left":5},"border_color":""}}]],"model":{"rows":[[{"value":"Translator","cspan":1,"rspan":1,"markup":[1,10]},{"value":"quest. OR corr.","cspan":1,"rspan":1,"markup":[1,15]},{"value":"quest. AND corr.","cspan":1,"rspan":1,"markup":[1,16]},{"value":"only quest.","cspan":1,"rspan":1,"markup":[1,11]},{"value":"none","cspan":1,"rspan":1,"markup":[1,4]}],[{"value":"LaTeX2Sympy","cspan":1,"rspan":1,"markup":[1,11]},{"value":"48%","cspan":1,"rspan":1,"markup":[1,3]},{"value":"20%","cspan":1,"rspan":1,"markup":[1,3]},{"value":"29%","cspan":1,"rspan":1,"markup":[1,3]},{"value":"52%","cspan":1,"rspan":1,"markup":[1,3]}],[{"value":"LaCASt","cspan":1,"rspan":1,"markup":[0,6]},{"value":"44%","cspan":1,"rspan":1,"markup":[1,3]},{"value":"26%","cspan":1,"rspan":1,"markup":[1,3]},{"value":"18%","cspan":1,"rspan":1,"markup":[1,3]},{"value":"56%","cspan":1,"rspan":1,"markup":[1,3]}]]},"theme":null,"fixed_layout":false,"markup":{"instances":[{},{"style":{"fontWeight":"","fontStyle":"","textDecoration":"","color":"","backgroundColor":""}}]},"options":{"table_caption":"","table_label":"tab:my-table"}} -------------------------------------------------------------------------------- /module5_solution_value_and_unit_check.py: -------------------------------------------------------------------------------- 1 | import sympy 2 | import re 3 | 4 | def get_lhs_identifier_properties(formula_identifiers): 5 | """Get left-hand side identifier name and symbol.""" 6 | identifier_name = formula_identifiers[0][1] 7 | identifier_symbol = formula_identifiers[0][0] 8 | return identifier_name, identifier_symbol 9 | 10 | def get_answer_value_and_unit(answer_input): 11 | """Get answer value and unit from parsing user answer input.""" 12 | answer_value_unit = answer_input.split() 13 | if len(answer_value_unit) == 1: 14 | print("Please input value AND unit (space-separated)!") 15 | answer_value = None 16 | answer_unit = None 17 | elif len(answer_value_unit) > 1: 18 | answer_value = answer_value_unit[0] 19 | answer_unit = ' '.join(answer_value_unit[1:]) 20 | 21 | return answer_value,answer_unit 22 | 23 | def check_value(solution_value,answer_value): 24 | """Check if input value corresponds to formula value.""" 25 | #answer_value = sympy.Rational(answer_value) 26 | value_correct = answer_value == solution_value 27 | 28 | # allow for float tolerance of +- 1% 29 | try: 30 | tolerance = 1/100 31 | answer_value = sympy.sympify(answer_value.replace(",", ".")) 32 | solution_value = sympy.sympify(solution_value) 33 | answer_solution_ratio = float(answer_value)/float(solution_value) 34 | if 1-tolerance < answer_solution_ratio < 1+tolerance: 35 | value_correct = True 36 | except: 37 | pass 38 | 39 | return value_correct 40 | 41 | def clean_unit_answer(answer_unit): 42 | # find '/', only clean/works if single occurrence 43 | if len(answer_unit.count('/')) == 1: 44 | for delimiter in ['/(.*)', '/(.*) ', ' /(.*)', ' /(.*) ']: 45 | try: 46 | match = re.search(delimiter,answer_unit) 47 | if match is not None: 48 | match = match.group(0) 49 | if not '^' in match: 50 | # exponent is (-)1 51 | replacement = match.replace('/','') + '^-1' 52 | else: 53 | # other exponents 54 | # remove '/' 55 | replacement = match.replace('/','') 56 | # switch exponent sign 57 | if '-' in replacement: 58 | replacement = replacement.replace('-', '') 59 | elif '+' in replacement: 60 | replacement = replacement.replace('+', '-') 61 | else: 62 | replacement = replacement.replace('^', '^-') 63 | answer_unit = answer_unit.replace(match, ' ' + replacement) 64 | except: 65 | pass 66 | 67 | return answer_unit 68 | 69 | def check_unit(formula_unit_dimension,answer_unit): 70 | """Check if input unit corresponds to formula unit.""" 71 | #unit_correct = answer_unit == formula_unit_dimension 72 | try: 73 | # clean 74 | #answer_unit = clean_unit_answer(answer_unit) 75 | # sets (for unit sequence invariance) 76 | answer_units = set(answer_unit.split()) 77 | correct_units = set(formula_unit_dimension.split()) 78 | # check 79 | unit_correct = answer_units == correct_units 80 | 81 | except: 82 | unit_correct = False 83 | 84 | if not unit_correct: 85 | try: 86 | # check sympy unit rearrangements 87 | unit_correct =\ 88 | sympy.sympify(answer_unit.replace(' ','*'))\ 89 | == sympy.sympify(formula_unit_dimension.replace(' ','*')) 90 | except: 91 | pass 92 | 93 | return unit_correct -------------------------------------------------------------------------------- /login/utils/sql_tools.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ########################## import packages ##################### 3 | ################################################################################ 4 | import mysql.connector as MySQLdb 5 | import sys 6 | sys.path.insert(0,'../.') 7 | import config 8 | import pandas as pd 9 | 10 | ################################################################################ 11 | ########################## Create Database on mysql server ##################### 12 | ################################################################################ 13 | def create_db(mysql_user=config.mysql_user, mysql_password=config.mysql_password ,mysql_host=config.mysql_host, db_name=config.db_name): 14 | try: 15 | conn = MySQLdb.connect(user=mysql_user, host=mysql_host, password=mysql_password) 16 | print('Connection to mysql server Done : success') 17 | try: 18 | cur = conn.cursor() 19 | cur.execute("CREATE DATABASE IF NOT EXISTS "+db_name+" ;") 20 | conn.commit() 21 | print("database created with success") 22 | finally: 23 | conn.close() 24 | print("connection closed !") 25 | except: 26 | print("I am unable to connect to the database") 27 | 28 | 29 | ################################################################################ 30 | ########################## Create Database on mysql server ##################### 31 | ################################################################################ 32 | def create_table(mysql_user=config.mysql_user, mysql_password=config.mysql_password ,mysql_host=config.mysql_host,table_name=config.table_name, db_name=config.db_name): 33 | try: 34 | conn = MySQLdb.connect(user=mysql_user, host=mysql_host, password=mysql_password, database=db_name) 35 | print('Connection to mysql server Done : success') 36 | try: 37 | cur = conn.cursor() 38 | cur.execute("""CREATE TABLE IF NOT EXISTS %s (id INT AUTO_INCREMENT PRIMARY KEY, 39 | email varchar(250), 40 | name varchar(250), 41 | password varchar(250) 42 | );""" %(table_name)) 43 | conn.commit() 44 | print("Table created with success") 45 | finally: 46 | conn.close() 47 | print("connection closed !") 48 | 49 | except: 50 | print("I am unable to connect to the database") 51 | 52 | def insert_row(email, name, password, user_name=config.mysql_user, mysql_password=config.mysql_password, host_name=config.mysql_host, db_name=config.db_name, table_name=config.table_name): 53 | # Define our connection string 54 | conn = MySQLdb.connect(user=user_name, password=mysql_password, host=host_name, database=db_name) 55 | try: 56 | cursor = conn.cursor() 57 | cursor.execute("""insert into %s (email, name, password) values ('%s', '%s', '%s'); """ %(table_name, email, name, password)) 58 | conn.commit() 59 | finally: 60 | conn.close() 61 | print('Row inserted') 62 | 63 | 64 | def import_data(query, mysql_user=config.mysql_user, mysql_password=config.mysql_password, mysql_host=config.mysql_host): 65 | try: 66 | conn = MySQLdb.connect(user=mysql_user, host=mysql_host, password=mysql_password) 67 | print('Connection to mysql server Done : success') 68 | print(query) 69 | except: 70 | print("I am unable to connect to the database") 71 | try: 72 | cur = conn.cursor() 73 | cur.execute(query) 74 | results = cur.fetchall() 75 | data = pd.DataFrame(list(results), columns=[row[0] for row in cur.description]).reset_index(drop=True) 76 | print(data) 77 | finally: 78 | conn.close() 79 | return (data) 80 | -------------------------------------------------------------------------------- /evaluation/module_workflow/unit_test_module_workflow_latex2sympy_evaluated(0).csv: -------------------------------------------------------------------------------- 1 | GoldID;QID;Name;Working;Identifier Properties;Formula unit;Identifier units;Formula sympy;Identifiers sympy;Sympy rhs 2 | 310;Q11376;acceleration;yes;idf;yes;yes;yes;yes;yes 3 | 311;Q186300;angular acceleration;part;idf;yes;yes;no;yes;no 4 | 312;Q834020;angular frequency;yes;idf;yes;yes;yes;yes;yes 5 | 313;Q161254;angular momentum;yes;idf;yes;yes;yes;yes;yes 6 | 314;Q161635;angular velocity;part;idf;yes;no;no;no;no 7 | 315;Q2945123;center of mass;no;cf, idf;no;no;no;no;no 8 | 316;Q2248131;centripetal acceleration;part;cf, idf;yes;yes;no;yes;no 9 | 317;Q172881;centripetal force;part;hp;yes;yes;no;yes;no 10 | 318;Q843905;circumference;part;cf;yes;yes;no;yes;no 11 | 319;Q11382;conservation of energy;part;hp;no;yes;no;yes;no 12 | 320;Q2305665;conservation of momentum;no;-;no;no;yes;no;no 13 | 321;Q1127660;damping;no;hp;no;no;no;no;no 14 | 322;Q272621;Dirac equation;no;hp;no;no;no;no;no 15 | 323;Q16853908;Dirac equation in curved spacetime;no;hp;no;no;yes;no;yes 16 | 324;Q891408;elastic energy;part;cf, idf;yes;yes;yes;yes;no 17 | 325;Q849919;electromagnetic force;no;hp;no;no;yes;no;yes 18 | 326;Q103438301;electrostatic force;part;hp;no;yes;no;yes;no 19 | 327;Q103439852;energy-momentum relation;part;hp;no;yes;no;yes;no 20 | 328;Q166530;escape velocity;no;cf;yes;no;no;no;no 21 | 329;Q875744;Euler–Lagrange equation;no;hp;no;no;no;no;no 22 | 330;Q11402;force;yes;cf, idf;yes;yes;yes;yes;yes 23 | 331;Q1068463;four-momentum;part;hp;no;yes;no;yes;no 24 | 332;Q1322540;four-velocity;no;hp;no;no;yes;no;yes 25 | 333;Q140028;free fall;no;hp;no;no;yes;no;yes 26 | 334;Q11652;frequency;yes;idf;yes;yes;yes;yes;yes 27 | 335;Q82580;friction;no;cf, idf;yes;no;no;no;no 28 | 336;Q219207;Galilean transformation;no;hp;no;no;no;no;no 29 | 337;Q6806305;generalized momentum;no;cf, idf;no;no;no;no;no 30 | 338;Q30006;gravitational acceleration;no;hp, cf, idf;yes;no;yes;no;yes 31 | 339;Q11412;gravity;no;hp;yes;no;no;no;no 32 | 340;Q1544012;gravitational potential;no;hp;yes;no;no;no;no 33 | 341;Q660488;Hamiltonian operator;no;-;no;no;no;no;no 34 | 342;Q1060137;Hamilton–Jacobi equation;no;cf;no;no;yes;no;yes 35 | 343;Q170282;Hooke's law;yes;hp;yes;yes;yes;yes;yes 36 | 344;Q497332;jerk;yes;cf, idf;yes;yes;yes;yes;yes 37 | 345;Q46276;kinetic energy;yes;idf;yes;yes;yes;yes;yes 38 | 346;Q103687426;Lagrangian operator;no;hp;no;no;yes;no;yes 39 | 347;Q599404;Lorentz factor;part;hp;no;yes;no;yes;no 40 | 348;Q172137;Lorentz force;no;cf, idf;yes;no;yes;no;yes 41 | 349;Q217255;Lorentz transformation;no;hp;no;no;yes;no;yes 42 | 350;Q35875;mass–energy equivalence;yes;idf;no;yes;yes;yes;yes 43 | 351;Q6421317;mechanical impedance;yes;cf, idf;yes;yes;yes;yes;yes 44 | 352;Q165618;moment of inertia;part;cf, idf;yes;yes;no;yes;no 45 | 353;Q41273;momentum;yes;idf;yes;yes;yes;yes;yes 46 | 354;Q2397319;Newton's second law of motion for constant mass;no;hp, idf;no;no;yes;no;yes 47 | 355;Q3235565;Newton's third law of motion;part;hp;no;yes;yes;yes;no 48 | 356;Q170475;oscillation;no;hp;no;no;yes;no;yes 49 | 357;Q20702;pendulum;no;hp;no;no;yes;no;yes 50 | 358;Q25342;power;part;cf, idf;yes;yes;no;yes;no 51 | 359;Q240105;radial velocity;no;hp;yes;no;no;no;no 52 | 360;Q11663629;rest energy;part;cf, idf;yes;yes;no;yes;no 53 | 361;Q96941619;rest mass;part;cf;yes;yes;no;yes;no 54 | 362;Q676622;Rossby number;no;cf, idf;no;no;no;no;no 55 | 363;Q3711325;speed;yes;idf;yes;yes;yes;yes;yes 56 | 364;Q2111;speed of light;part;cf;yes;yes;no;yes;no 57 | 365;Q12507;sphere;no;hp;no;no;no;no;no 58 | 366;Q3299367;Spherical pendulum;no;hp;no;no;no;no;no 59 | 367;Q824561;Stokes' law;no;hp;no;no;no;no;no 60 | 368;Q206175;stress;no;hp, cf;yes;no;yes;no;yes 61 | 369;Q2822927;stress;no;hp, cf;yes;no;yes;no;yes 62 | 370;Q103715245;tangential velocity;yes;hp;no;yes;yes;yes;yes 63 | 371;Q48103;torque;no;idf;yes;no;yes;no;yes 64 | 372;Q376742;uniform motion;no;hp;no;no;yes;no;yes 65 | 373;Q11465;velocity;no;hp, idf;yes;no;no;no;no 66 | 374;Q192510;wavenumber;part;idf;yes;yes;yes;yes;yes 67 | 375;Q42213;work;part;idf;yes;yes;no;yes;no 68 | ;;;;;;;;; 69 | ;;;13 yes, 34 no, 19 part -> 48% question or correction, 20% question and correction, 29% question, 52% none;33 hp, 21 cf, 29 idf, 2 none;35 yes;31 yes;33 yes;31 yes;30 yes 70 | ;;;;;35;31;33;31;30 71 | ;;;;;0,53030303;0,46969697;0,5;0,46969697;0,454545455 72 | ;;;48;97;53;47;50;47;45 73 | -------------------------------------------------------------------------------- /old/module_outputs0.py: -------------------------------------------------------------------------------- 1 | #TODO: slow down print out process 2 | #TODO: print out ALL retrieved variables 3 | 4 | # ISSUES: 5 | #TODO: module3.get_random_identifier_values 6 | # strToSympy parsing \frac, etc. 7 | #TODO: module5.check_value: 8 | # allow percentage float tolerance for answer value 9 | 10 | from old import module0_formula_and_identifier_retrieval as module0, module1_identifier_unit_retrieval as module1 11 | import module3_identifier_value_generation as module3 12 | import module4_question_text_generation as module4 13 | import module5_solution_value_and_unit_check as module5 14 | 15 | def generate_question(name): 16 | 17 | ############################################## 18 | # Module 0: Formula and Identifier Retrieval # 19 | ############################################## 20 | 21 | # INSTRUCTOR INPUT 22 | 23 | # Module 0.0: Input Formula Concept name 24 | print('\nInput Formula Concept name: ',name) 25 | 26 | # Get QID from name 27 | print('\nRetrieving Wikidata item qid...\n') 28 | qid = module0.get_qid_sparql_with_defining_formula(name) 29 | print(f'Retrieving formula concept for qid >>{qid}<<...\n') 30 | 31 | # Get item from QID 32 | print('\nRetrieving Wikidata item...\n') 33 | item = module0.get_Wikidata_item(qid) 34 | 35 | # Module 0.1: Get concept name from item 36 | concept_name = module0.get_concept_name(item) 37 | print(f'Retrieving formula concept name: >>{concept_name}<<\n') 38 | 39 | # System output for processing question 40 | print(f'Generating physics formula question for >>{concept_name}<<...\n') 41 | 42 | # Module 0.2: Get defining formula 43 | defining_formula = module0.get_defining_formula(item) 44 | print(f'Retrieving defining formula: >>{defining_formula}<<\n') 45 | 46 | # Module 0.3: Get formula identifier (symbol, name) tuples 47 | print('Retrieving formula identifier symbols and names...\n') 48 | formula_identifiers = module0.get_formula_identifiers(item) 49 | 50 | ####################################### 51 | # Module 1: Identifier Unit Retrieval # 52 | ####################################### 53 | 54 | print('Retrieving formula identifier units...\n') 55 | formula_unit_dimension = module1.get_formula_unit_dimension(item) 56 | identifier_unit_dimensions = module1.get_identifier_unit_dimensions(item) 57 | formula_identifiers = module1.update_identifiers_dict(formula_identifiers,formula_unit_dimension,identifier_unit_dimensions) 58 | 59 | ################################### 60 | # Module 2: Formula Rearrangement # 61 | ################################### 62 | 63 | print('Generating formula rearrangements...\n') 64 | # Get formula rearrangements using Computer Algebra Systems (CAS), maybe SymPy 65 | #formula_rearrangements = module2.get_random_formula_rearrangements(defining_formula) 66 | 67 | ######################################### 68 | # Module 3: Identifier Value Generation # 69 | ######################################### 70 | 71 | print('Generating random identifier values...\n') 72 | identifier_values = module3.get_random_identifier_values(formula_identifiers,defining_formula) 73 | 74 | ###################################### 75 | # Module 4: Question Text Generation # 76 | ###################################### 77 | 78 | print('Generating formula question text...\n') 79 | question_text = module4.get_question_text(formula_identifiers,identifier_values,identifier_unit_dimensions) 80 | print(question_text) 81 | 82 | return question_text,identifier_values,formula_unit_dimension 83 | 84 | def correct_answer(correct_value,correct_unit,answer_input): 85 | 86 | # STUDENT INPUT 87 | 88 | print('Get student answer input...\n') 89 | answer_value, answer_unit = module5.get_answer_value_and_unit(answer_input) 90 | print(f'Answer value: {answer_value}') 91 | print(f'Answer unit: {answer_unit}\n') 92 | 93 | ########################################### 94 | # Module 5: Solution Value and Unit Check # 95 | ########################################### 96 | 97 | print('Check answer value and unit...\n') 98 | # check solution value 99 | value_correct = module5.check_value(correct_value,answer_value) 100 | print(f'Solution value: {correct_value}') 101 | print(f'Answer value: {answer_value}') 102 | if value_correct: 103 | print('Value answer correct!') 104 | else: 105 | print('Value answer incorrect!') 106 | 107 | print() 108 | # check solution unit 109 | unit_correct = module5.check_unit(correct_unit,answer_unit) 110 | print(f'Solution unit: {correct_unit}') 111 | print(f'Answer unit: {answer_unit}') 112 | if unit_correct: 113 | print('Unit answer correct!') 114 | else: 115 | print('Unit answer incorrect!') 116 | 117 | return value_correct,unit_correct -------------------------------------------------------------------------------- /module_outputs.py: -------------------------------------------------------------------------------- 1 | # TODO: slow down print out process 2 | # TODO: print out ALL retrieved variables 3 | 4 | # ISSUES: 5 | # TODO: module3.get_random_identifier_values 6 | # strToSympy parsing \frac, etc. 7 | # TODO: module5.check_value: 8 | # allow percentage float tolerance for answer value 9 | 10 | import benchmark_cache 11 | import module1_formula_and_identifier_retrieval as module1 12 | import module2_formula_rearrangement as module2 13 | import module3_identifier_value_generation as module3 14 | import module4_question_text_generation as module4 15 | import module5_solution_value_and_unit_check as module5 16 | import module6_explanation_text_generation as module6 17 | 18 | 19 | def generate_question(name): 20 | ############################################## 21 | # Module 1: Formula and Identifier Retrieval # 22 | ############################################## 23 | 24 | # INSTRUCTOR INPUT 25 | 26 | # Input Formula Concept name 27 | print('\nInput Formula Concept name: ', name) 28 | 29 | # If not QID, get QID from name 30 | print('\nRetrieving Wikidata item qid...\n') 31 | if name.startswith('Q') and name[1:].isnumeric(): 32 | qid = name 33 | else: 34 | qid = module1.get_qid_pywikibot(name) 35 | if qid == 'N/A': 36 | qid = module1.get_qid_sparql_with_defining_formula(name) 37 | print(f'Retrieving formula concept for qid >>{qid}<<...\n') 38 | 39 | # Get item from QID 40 | print('\nRetrieving Wikidata item...\n') 41 | # Check if in benchmark sample dataset 42 | try: 43 | sample_items = benchmark_cache.load_benchmark_dump() 44 | item = sample_items[qid] 45 | except: 46 | item = None 47 | # Load item (json) data 48 | try: 49 | if item is None: 50 | item = module1.get_Wikidata_item(qid) 51 | except: 52 | return 'No Wikidata item with formula found', None, None, '' 53 | 54 | # Get concept name from item 55 | # concept_name = module1.get_concept_name(item) 56 | # print(f'Retrieving formula concept name: >>{concept_name}<<\n') 57 | 58 | # System output for processing question 59 | print(f'Generating physics formula question for >>{name}<<...\n') 60 | 61 | # Get defining formula 62 | try: 63 | defining_formula = module1.get_defining_formula(item) 64 | except: 65 | return 'Defining formula retrieval unsuccessful', None, None, '' 66 | print(f'Retrieved defining formula: >>{defining_formula}<<\n') 67 | 68 | # Get formula unit dimension 69 | # formula_unit_dimension = module1.get_formula_unit_dimension(item) 70 | 71 | # Get formula identifier property (name, symbol, unit) triples 72 | print('Retrieving formula identifier properties...\n') 73 | try: 74 | formula_identifiers = module1.get_identifier_properties(item) 75 | except: 76 | return 'Identifier property retrieval unsuccessful', None, None, '' 77 | if len(formula_identifiers) == 0: 78 | return 'Identifier property retrieval unsuccessful', None, None, '' 79 | 80 | ################################### 81 | # Module 2: Formula Rearrangement # 82 | ################################### 83 | 84 | print('Generating formula rearrangements...\n') 85 | # Get formula rearrangements using Computer Algebra Systems (CAS), SymPy 86 | defining_formula, formula_identifiers, formula_unit_dimension = module2.get_random_formula_rearrangements( 87 | defining_formula, formula_identifiers) 88 | 89 | ######################################### 90 | # Module 3: Identifier Value Generation # 91 | ######################################### 92 | 93 | print('Generating random identifier values...\n') 94 | try: 95 | identifier_values = module3.get_random_identifier_values(formula_identifiers, defining_formula) 96 | except: 97 | return 'Identifier value generation unsuccessful', None, None, '' 98 | if len(identifier_values) == 0: 99 | return 'Identifier value generation unsuccessful', None, None, '' 100 | 101 | ###################################### 102 | # Module 4: Question Text Generation # 103 | ###################################### 104 | 105 | print('Generating formula question text...\n') 106 | question_text = module4.get_question_text(formula_identifiers, identifier_values) 107 | print(question_text) 108 | 109 | ######################################### 110 | # Module 6: Explanation Text Generation # 111 | ######################################### 112 | 113 | explanation_text = module6.generate_explanation_text(qid, defining_formula, formula_identifiers, identifier_values) 114 | 115 | return question_text, identifier_values, formula_unit_dimension, explanation_text 116 | 117 | 118 | def correct_answer(correct_value, correct_unit, answer_input): 119 | # STUDENT INPUT 120 | 121 | print('Get student answer input...\n') 122 | answer_value, answer_unit = module5.get_answer_value_and_unit(answer_input) 123 | print(f'Answer value: {answer_value}') 124 | print(f'Answer unit: {answer_unit}\n') 125 | 126 | ########################################### 127 | # Module 5: Solution Value and Unit Check # 128 | ########################################### 129 | 130 | print('Check answer value and unit...\n') 131 | # check solution value 132 | value_correct = module5.check_value(correct_value, answer_value) 133 | print(f'Solution value: {correct_value}') 134 | print(f'Answer value: {answer_value}') 135 | if value_correct: 136 | print('Value answer correct!') 137 | else: 138 | print('Value answer incorrect!') 139 | 140 | print() 141 | # check solution unit 142 | unit_correct = module5.check_unit(correct_unit, answer_unit) 143 | print(f'Solution unit: {correct_unit}') 144 | print(f'Answer unit: {answer_unit}') 145 | if unit_correct: 146 | print('Unit answer correct!') 147 | else: 148 | print('Unit answer incorrect!') 149 | 150 | return value_correct, unit_correct 151 | -------------------------------------------------------------------------------- /login/main.py: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | ###################### Import packages ################################### 3 | ######################################################################################## 4 | from flask import Blueprint, render_template, request, flash 5 | from flask_login import login_required, current_user 6 | from __init__ import create_app, db 7 | from module_outputs import generate_question,correct_answer 8 | import json 9 | 10 | ######################################################################################## 11 | # our main blueprint 12 | main = Blueprint('main', __name__) 13 | 14 | @main.route('/') # home page that return 'index' 15 | def index(): 16 | return render_template('index.html') 17 | 18 | # PROFILE 19 | 20 | @main.route('/profile') # profile page that return 'profile' 21 | @login_required 22 | def profile(): 23 | return render_template('profile.html', name=current_user.name) 24 | 25 | # POST 26 | 27 | def my_form_post(): 28 | 29 | # Init variables 30 | concept = '' 31 | answer = '' 32 | correction = '' 33 | explanation = '' 34 | 35 | # Read from cache 36 | with open('cache.json', 'r') as f: 37 | cache = json.load(f) 38 | concept = cache['concept'] 39 | question = cache['question'] 40 | 41 | if 'concept' in request.form:# and cache['question_generated']==False: 42 | 43 | # QUESTION GENERATION 44 | try: 45 | concept = request.form['concept'] 46 | question = 'Unknown error' 47 | question_text, identifier_info, formula_info, explanation = generate_question(concept) 48 | question = question_text 49 | cache['correct_value'] = str(identifier_info[0]) 50 | cache['correct_unit'] = formula_info 51 | cache['explanation'] = explanation 52 | explanation = '' 53 | cache['question_generated'] = True 54 | except: 55 | pass 56 | #question = 'Question could not be generated' 57 | 58 | if 'answer' in request.form:# and cache['question_generated']==True: 59 | 60 | # ANSWER CORRECTION 61 | try: 62 | answer = request.form['answer'] 63 | value_correct, unit_correct = correct_answer(cache['correct_value'],cache['correct_unit'],answer) 64 | # Set correction text 65 | # correction = value_correct, unit_correct 66 | # correction = 'Value answer correct: ' + str(value_correct) + ", " + 'Unit answer correct: ' + str(unit_correct) 67 | value_prefix = 'Value ' 68 | unit_prefix = 'Unit ' 69 | if value_correct: 70 | value_suffix = 'correct!' 71 | elif not value_correct: 72 | value_suffix = 'incorrect!' 73 | if unit_correct: 74 | unit_suffix = 'correct!' 75 | elif not unit_correct: 76 | unit_suffix = 'incorrect!' 77 | value_text = value_prefix + value_suffix 78 | unit_text = unit_prefix + unit_suffix 79 | # TODO: add Wikipedia URL to correction text 80 | explanation = cache['explanation'] 81 | correction = ' '.join([value_text,unit_text]) 82 | # No question given 83 | if not '=' in question: 84 | correction = 'No question given' 85 | explanation = '' 86 | # Wrong format 87 | if len(answer.split()) < 2: 88 | correction = 'Please input value AND unit (space-separated)!' 89 | explanation = '' 90 | cache['question_generated'] = False 91 | 92 | except: 93 | pass 94 | 95 | # Write to cache 96 | cache['concept'] = concept 97 | cache['question'] = question 98 | with open('cache.json', 'w') as f: 99 | json.dump(cache,f) 100 | 101 | return {'concept':concept,'question':question, 102 | 'answer':answer,'correction':correction,'explanation':explanation} 103 | 104 | # TEACHER 105 | 106 | @main.route('/teacher') 107 | @login_required 108 | def teacher(): 109 | #return render_template('teacher.html') 110 | r = my_form_post() 111 | return render_template('teacher.html', 112 | concept=r['concept'], question=r['question'], 113 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 114 | 115 | @main.route('/teacher',methods=['POST']) 116 | @login_required 117 | def teacher_post(): 118 | r = my_form_post() 119 | return render_template('teacher.html', 120 | concept=r['concept'], question=r['question'], 121 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 122 | 123 | # STUDENT 124 | 125 | @main.route('/student') 126 | @login_required 127 | def student(): 128 | #return render_template('student.html') 129 | r = my_form_post() 130 | return render_template('student.html', 131 | concept=r['concept'], question=r['question'], 132 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 133 | 134 | @main.route('/student',methods=['POST']) 135 | @login_required 136 | def student_post(): 137 | r = my_form_post() 138 | return render_template('student.html', 139 | concept=r['concept'], question=r['question'], 140 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 141 | 142 | # MAIN APP 143 | 144 | app = create_app() # we initialize our flask app using the __init__.py function 145 | if __name__ == '__main__': 146 | db.create_all(app=create_app()) # create the SQLite database 147 | app.run(debug=True) # run the flask app on debug mode -------------------------------------------------------------------------------- /module_workflow.py: -------------------------------------------------------------------------------- 1 | #TODO: slow down print out process 2 | #TODO: print out ALL retrieved variables 3 | 4 | # ISSUES: 5 | #TODO: module3.get_random_identifier_values 6 | # strToSympy parsing \frac, etc. 7 | #TODO: module5.check_value: 8 | # allow percentage float tolerance for answer value 9 | 10 | #TODO: enable concept name input, e.g., 'speed' or 'acceleration' instead of QID 11 | 12 | #TODO: extend cleanings (integral, greek letters \, variable interchange, x(t) -> x_t) 13 | 14 | import module1_formula_and_identifier_retrieval as module1 15 | import module2_formula_rearrangement as module2 16 | import module3_identifier_value_generation as module3 17 | import module4_question_text_generation as module4 18 | import module5_solution_value_and_unit_check as module5 19 | 20 | ############################################## 21 | # Module 1: Formula and Identifier Retrieval # 22 | ############################################## 23 | 24 | # INSTRUCTOR INPUT 25 | 26 | # Input formula question QID 27 | #qid = input('Input formula question QID:') 28 | # Example 29 | #qid = 'Q11376'#: 'acceleration' 30 | qid = 'Q11652'# 'frequency': 31 | #qid = 'Q35875'# 'mass-energy equivalence' 32 | #qid = 'Q2397319'# 'Newton's second law of motion for constant mass' 33 | #qid = 'Q3711325'# 'speed' 34 | print('\nInput formula question QID: ',qid) 35 | 36 | # Get item from QID 37 | print('\nRetrieving Wikidata item...\n') 38 | item = module1.get_Wikidata_item(qid) 39 | 40 | # Get concept name from item 41 | concept_name = module1.get_concept_name(item) 42 | print(f'Retrieving formula concept name: >>{concept_name}<<\n') 43 | # Example 44 | #concept_name = 'acceleration' 45 | 46 | # System output for processing question 47 | print(f'Generating physics formula question for >>{concept_name}<<...\n') 48 | # Example 49 | #print('Generating physics formula question for >>acceleration<<...') 50 | 51 | # Get defining formula 52 | defining_formula = module1.get_defining_formula(item) 53 | print(f'Retrieving defining formula: >>{defining_formula}<<\n') 54 | # Example 55 | # 'defining formula' (P2534) = 'a = dv/dt' 56 | #defining_formula = '\\boldsymbol{a} = \\frac{\\mathrm{d} \\boldsymbol{v}}{\\mathrm{d} t}' 57 | 58 | # Get formula unit dimension 59 | formula_unit_dimension = module1.get_formula_unit_dimension(item) 60 | 61 | print('Retrieving formula identifier properties...\n') 62 | formula_identifiers = module1.get_identifier_properties(item) 63 | # Get formula identifier (symbol, name) tuples 64 | print('Retrieving formula identifier symbols and names...\n') 65 | # Example 66 | #formula_identifiers = [('a', 'acceleration'), ('v', 'velocity'), ('t', 'duration')] 67 | # a: 'acceleration' (Q11376) 68 | # v: 'velocity' (Q11465) 69 | # t: 'duration' (Q2199864) 70 | print('Retrieving formula identifier units...\n') 71 | # Get formula identifier property (name, symbol, unit) triples 72 | # Example 73 | # 'ISQ dimension' property (P4020) = 'LT^-2 74 | #formula_unit_dimensions = '\mathsf{L} \mathsf{T}^{-2}' 75 | #identifier_unit_dimensions = ['\\mathsf{L} \\mathsf{T}^{-1}', '\\mathsf{T}'] 76 | 77 | ################################### 78 | # Module 2: Formula Rearrangement # 79 | ################################### 80 | 81 | print('Generating formula rearrangements...\n') 82 | # Get formula rearrangements using Computer Algebra Systems (CAS), maybe SymPy 83 | #formula_rearrangements = module2.get_random_formula_rearrangements(defining_formula) 84 | # Example 85 | #formula_rearrangements = ['a = v/t', 'v = a t','t = v/a'] 86 | 87 | ######################################### 88 | # Module 3: Identifier Value Generation # 89 | ######################################### 90 | 91 | print('Generating random identifier values...\n') 92 | identifier_values = module3.get_random_identifier_values(formula_identifiers,defining_formula) 93 | # (randomize) 94 | # Example 95 | #identifier_values = [3,6,2]#, [6,3,2], [2,6,3] # [a,v,t] 96 | 97 | ###################################### 98 | # Module 4: Question Text Generation # 99 | ###################################### 100 | 101 | print('Generating formula question text...\n') 102 | question_text = module4.get_question_text(formula_identifiers,identifier_values) 103 | # Example 104 | #question_text = 'What is the acceleration a, given velocity v = 6 m/s and time t = 2 s ?' # a = v/t = 3 m/s^2 105 | # a) 'What is the force F, given mass m = 2 kg and acceleration a = 3 m/s^2 ?' 106 | # b) 'What is the mass m, given force F = 6 N and acceleration a = 3 m/s^2 ?' 107 | # c) 'What is the acceleration a, given Force F = 6 N and mass m = 2 kg ?' 108 | # (randomize) 109 | print(question_text,'\n') 110 | 111 | ############# 112 | 113 | # STUDENT INPUT 114 | 115 | print('Get student answer input...\n') 116 | identifier_name, identifier_symbol = module5.get_lhs_identifier_properties(formula_identifiers) 117 | answer_unit = None 118 | while answer_unit == None: 119 | answer_input = input(f'{identifier_name} {identifier_symbol} = ?') 120 | answer_value,answer_unit = module5.get_answer_value_and_unit(answer_input) 121 | print('\nParse answer input...\n') 122 | print(f'Answer value: {answer_value}') 123 | print(f'Answer unit: {answer_unit}\n') 124 | # Example 125 | # a = 3 m/s^2 126 | 127 | ########################################### 128 | # Module 5: Solution Value and Unit Check # 129 | ########################################### 130 | 131 | print('Check answer value and unit...\n') 132 | # check solution value 133 | solution_value = identifier_values[0] 134 | value_correct = module5.check_value(solution_value,answer_value) 135 | #value_correct = True 136 | print(f'Solution value: {solution_value}') 137 | print(f'Answer value: {answer_value}') 138 | if value_correct: 139 | print('Value answer correct!') 140 | else: 141 | print('Value answer incorrect!') 142 | # 'correct' 143 | print() 144 | # check solution unit 145 | solution_unit = formula_unit_dimension 146 | unit_correct = module5.check_unit(solution_unit,answer_unit) 147 | #unit_correct = True 148 | print(f'Solution unit: {formula_unit_dimension}') 149 | print(f'Answer unit: {answer_unit}') 150 | if unit_correct: 151 | print('Unit answer correct!') 152 | else: 153 | print('Unit answer incorrect!') 154 | # 'correct' 155 | 156 | print('\nEnd of system workflow.') -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, jsonify 2 | from module_outputs import generate_question,correct_answer 3 | import json 4 | 5 | #Flask tutorials: 6 | #https://web.itu.edu.tr/uyar/fad/forms.html 7 | #https://medium.com/analytics-vidhya/creating-login-page-on-flask-9d20738d9f42 8 | #https://programminghistorian.org/en/lessons/creating-apis-with-python-and-flask 9 | 10 | #TODO: multilinguality employing Wikidata 11 | #TODO: teacher and student login and question distribution 12 | #TODO: allow for formula string input (combine with MathQA functionality) 13 | #TODO: fix greek to latin converted letter duplicate issue 14 | 15 | app = Flask(__name__) 16 | 17 | # REQUEST 18 | 19 | @app.route('/api/v1', methods=['GET']) 20 | def api_qid(): 21 | # Check if a Wikidata item concept name or QID was provided as part of the URL. 22 | # If QID is provided, assign it to a variable. 23 | # If no QID is provided, display an error in the browser. 24 | if 'name' in request.args: 25 | name_qid = request.args['name'] 26 | elif 'qid' in request.args: 27 | name_qid = request.args['qid'] 28 | else: 29 | return "Error: No Wikidata item name or qid provided. Please specify a name or qid." 30 | 31 | # Generate response 32 | question = generate_question(name_qid) 33 | question_text = question[0] 34 | identifier_values = question[1] 35 | formula_unit_dimension = question[2] 36 | explanation_text = question[3] 37 | 38 | response = {'question_text': question_text, 'identifier_values': identifier_values, 39 | 'formula_unit_dimension': formula_unit_dimension, 'explanation_text': explanation_text} 40 | 41 | return jsonify(response) 42 | 43 | # POST 44 | 45 | def my_form_post(): 46 | 47 | # Init variables 48 | answer = '' 49 | correction = '' 50 | explanation = '' 51 | 52 | # Read from cache 53 | with open('cache.json', 'r') as f: 54 | cache = json.load(f) 55 | concept = cache['concept'] 56 | question = cache['question'] 57 | 58 | if 'concept' in request.form:# and cache['question_generated']==False: 59 | 60 | # QUESTION GENERATION 61 | try: 62 | concept = request.form['concept'] 63 | question = 'Unknown error' 64 | question_text, identifier_info, formula_info, explanation = generate_question(concept) 65 | question = question_text 66 | cache['correct_value'] = str(identifier_info[0]) 67 | cache['correct_unit'] = formula_info 68 | cache['explanation'] = explanation 69 | explanation = '' 70 | cache['question_generated'] = True 71 | except: 72 | pass 73 | #question = 'Question could not be generated' 74 | 75 | if 'answer' in request.form:# and cache['question_generated']==True: 76 | 77 | # ANSWER CORRECTION 78 | try: 79 | answer = request.form['answer'] 80 | value_correct, unit_correct = correct_answer(cache['correct_value'],cache['correct_unit'],answer) 81 | # Set correction text 82 | # correction = value_correct, unit_correct 83 | # correction = 'Value answer correct: ' + str(value_correct) + ", " + 'Unit answer correct: ' + str(unit_correct) 84 | value_prefix = 'Value ' 85 | unit_prefix = 'Unit ' 86 | if value_correct: 87 | value_suffix = 'correct!' 88 | elif not value_correct: 89 | value_suffix = 'incorrect!' 90 | if unit_correct: 91 | unit_suffix = 'correct!' 92 | elif not unit_correct: 93 | unit_suffix = 'incorrect!' 94 | value_text = value_prefix + value_suffix 95 | unit_text = unit_prefix + unit_suffix 96 | # TODO: add Wikipedia URL to correction text 97 | explanation = cache['explanation'] 98 | correction = ' '.join([value_text,unit_text]) 99 | # No question given 100 | if not '=' in question: 101 | correction = 'No question given' 102 | explanation = '' 103 | # Wrong format 104 | if len(answer.split()) < 2: 105 | correction = 'Please input value AND unit (space-separated)!' 106 | explanation = '' 107 | cache['question_generated'] = False 108 | 109 | except: 110 | pass 111 | 112 | # Write to cache 113 | cache['concept'] = concept 114 | cache['question'] = question 115 | with open('cache.json', 'w') as f: 116 | json.dump(cache,f) 117 | 118 | return {'concept':concept,'question':question, 119 | 'answer':answer,'correction':correction,'explanation':explanation} 120 | 121 | # TEACHER 122 | 123 | @app.route('/teacher') 124 | def teacher(): 125 | #return render_template('teacher.html') 126 | r = my_form_post() 127 | return render_template('teacher.html', 128 | concept=r['concept'], question=r['question'], 129 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 130 | 131 | @app.route('/teacher',methods=['POST']) 132 | def teacher_post(): 133 | r = my_form_post() 134 | return render_template('teacher.html', 135 | concept=r['concept'], question=r['question'], 136 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 137 | 138 | # STUDENT 139 | 140 | @app.route('/student') 141 | def student(): 142 | #return render_template('student.html') 143 | r = my_form_post() 144 | return render_template('student.html', 145 | concept=r['concept'], question=r['question'], 146 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 147 | 148 | @app.route('/student',methods=['POST']) 149 | def student_post(): 150 | r = my_form_post() 151 | return render_template('student.html', 152 | concept=r['concept'], question=r['question'], 153 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 154 | 155 | # MAIN APP 156 | 157 | @app.route('/') 158 | def app_form(): 159 | return render_template('my-form.html') 160 | 161 | @app.route('/', methods=['POST']) 162 | def app_form_post(): 163 | r = my_form_post() 164 | return render_template('select.html',concept=r['concept'], question=r['question'], 165 | answer=r['answer'], correction=r['correction'], explanation=r['explanation']) 166 | 167 | if __name__ == '__main__': 168 | app.run(host='0.0.0.0')#debug=True -------------------------------------------------------------------------------- /evaluation/module_workflow/integration_test.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | import itertools 4 | import random 5 | 6 | import sympy 7 | from latex2sympy2 import latex2sympy 8 | 9 | import requests 10 | 11 | import module1_formula_and_identifier_retrieval as module1 12 | import module3_identifier_value_generation as module3 13 | import module4_question_text_generation as module4 14 | import module6_explanation_text_generation as module6 15 | 16 | filename = 'unit_test_module_workflow_empty.csv' 17 | 18 | modes = ['latex2sympy','lacast'] 19 | mode = modes[1] 20 | 21 | def write_cell(col_name,row_idx,content): 22 | table.loc[table.index[row_idx],col_name] = str(content) 23 | 24 | table = pd.read_csv(filename,delimiter=';') 25 | qids = table['QID'] 26 | 27 | for idx in range(len(qids)): 28 | 29 | # QID 30 | qid = qids[idx] 31 | print(qid) 32 | write_cell('QID',idx,qid) 33 | 34 | # Item 35 | try: 36 | item = module1.get_Wikidata_item(qid) 37 | except: 38 | pass 39 | 40 | # Name 41 | try: 42 | name = module1.get_concept_name(item) 43 | print(name) 44 | except: 45 | name = 'N/A' 46 | write_cell('Name', idx, name) 47 | 48 | # Formula 49 | try: 50 | defining_formula = module1.get_defining_formula(item) 51 | print(defining_formula) 52 | except: 53 | defining_formula = 'N/A' 54 | write_cell('Formula', idx, defining_formula) 55 | 56 | # Properties 57 | def get_identifier_property_keys(item): 58 | 59 | keys = '' 60 | for identifier_property_key in ['P527', 'P4934', 'P7235']: 61 | try: 62 | item['claims'][identifier_property_key] is not None 63 | keys += identifier_property_key + ', ' 64 | except: 65 | pass 66 | 67 | return keys[:-2] 68 | try: 69 | identifier_property_keys = get_identifier_property_keys(item) 70 | print(identifier_property_keys) 71 | except: 72 | identifier_property_keys = 'N/A' 73 | write_cell('Properties', idx, identifier_property_keys) 74 | 75 | # Formula unit 76 | try: 77 | formula_unit = module1.get_formula_unit_dimension(item) 78 | print(formula_unit) 79 | except: 80 | formula_unit = 'N/A' 81 | write_cell('Formula unit', idx, formula_unit) 82 | 83 | # Formula sympy 84 | try: 85 | if mode == 'latex2sympy': 86 | formula_sympy = latex2sympy(defining_formula) 87 | elif mode == 'lacast': 88 | formula_sympy = module3.get_sympy_from_latex_using_vmext_api(defining_formula) 89 | print(formula_sympy) 90 | except: 91 | formula_sympy = 'N/A' 92 | write_cell('Formula sympy', idx, formula_sympy) 93 | 94 | # Identifiers 95 | try: 96 | formula_identifiers = module1.get_identifier_properties(item) 97 | print(formula_identifiers) 98 | except: 99 | formula_identifiers = 'N/A' 100 | write_cell('Identifiers', idx, str(formula_identifiers)) 101 | 102 | # Identifiers sympy 103 | try: 104 | identifiers_sympy = sympy.symbols(' '.join([identifier[1] for identifier in formula_identifiers])) 105 | print(identifiers_sympy) 106 | except: 107 | identifiers_sympy = 'N/A' 108 | write_cell('Identifiers sympy', idx, identifiers_sympy) 109 | 110 | # Sympy solve 111 | def get_sympy_solve(defining_formula,identifiers_sympy): 112 | 113 | formula_rearrangements = [] 114 | # Transform LaTeX to Sympy 115 | url = "https://vmext-demo.formulasearchengine.com/math/translation" 116 | params = {'cas': 'SymPy', 'genericExperimentalFeatures': 'true', 'latex': defining_formula} 117 | response = requests.post(url, params=params) 118 | formula_string = response.json()['result'] 119 | # translate formula lhs and rhs 120 | formula_lhs_sympy = sympy.sympify(formula_string.split("==")[0]) 121 | formula_rhs_sympy = sympy.sympify(formula_string.split("==")[1]) 122 | 123 | # Solve equation for different identifiers 124 | for identifier in identifiers_sympy: 125 | eq = sympy.Eq(lhs=formula_lhs_sympy, rhs=formula_rhs_sympy) 126 | formula_rearrangements.append((identifier, sympy.solve(eq, identifier))) 127 | 128 | return formula_rearrangements 129 | try: 130 | sympy_solve = get_sympy_solve(defining_formula,identifiers_sympy) 131 | print(sympy_solve) 132 | except: 133 | sympy_solve = 'N/A' 134 | write_cell('Sympy solve', idx, sympy_solve) 135 | 136 | # Sympy rhs 137 | def get_sympy_rhs(formula_sympy,formula_identifiers): 138 | 139 | rhs_identifier_values = [] 140 | 141 | # define limit for right-hand side integer value 142 | lower_val_limit = 1 143 | upper_val_limit = 10 144 | 145 | # generate random integers for right-hand side identifiers 146 | for _ in itertools.repeat(None, len(formula_identifiers) - 1): 147 | rhs_identifier_values.append(random.randint(lower_val_limit, upper_val_limit)) 148 | 149 | # substitute generated random values to calculate left-hand side 150 | identifier_index = 0 151 | for identifier_sympy in identifiers_sympy: 152 | if identifier_index != 0: # lhs identifier 153 | formula_sympy = formula_sympy.subs(identifier_sympy, rhs_identifier_values[identifier_index - 1]) 154 | identifier_index += 1 155 | try: 156 | lhs_identifier_value = formula_sympy.rhs 157 | except: 158 | lhs_identifier_value = formula_sympy 159 | 160 | return lhs_identifier_value 161 | try: 162 | sympy_rhs = get_sympy_rhs(formula_sympy,formula_identifiers) 163 | print(sympy_rhs) 164 | except: 165 | sympy_rhs = 'N/A' 166 | write_cell('Sympy rhs',idx,sympy_rhs) 167 | 168 | # Question 169 | try: 170 | identifier_values = module3.get_random_identifier_values(formula_identifiers, defining_formula) 171 | question_text = module4.get_question_text(formula_identifiers,identifier_values,) 172 | print(question_text) 173 | except: 174 | question_text = 'N/A' 175 | write_cell('Question', idx, question_text) 176 | 177 | # Explanation 178 | try: 179 | explanation_text = module6.generate_explanation_text(qid,defining_formula,formula_identifiers,identifier_values) 180 | print(explanation_text) 181 | except: 182 | explanation_text = 'N/A' 183 | write_cell('Explanation', idx, explanation_text) 184 | 185 | # Empty line 186 | print() 187 | 188 | table.to_csv('unit_test_module_workflow_' + mode + '_generated.csv') 189 | 190 | print('end') -------------------------------------------------------------------------------- /old/module0_formula_and_identifier_retrieval.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import string 3 | import requests 4 | import pywikibot 5 | import SPARQLWrapper 6 | 7 | # load cleanings 8 | cleanings_simple = [] 9 | with open('../latex_cleanings_simple.csv') as f: 10 | for row in csv.reader(f): 11 | cleanings_simple.append((row[0],row[1])) 12 | with open('../latex_cleanings_argument.txt') as f: 13 | cleanings_argument = f.readlines() 14 | 15 | def clean_latex(latex_string): 16 | """Clean LaTeX formula for converter.""" 17 | 18 | # argument cleanings 19 | alphabet = list(string.ascii_lowercase) + list(string.ascii_uppercase) 20 | for cleaning in cleanings_argument: 21 | for letter in alphabet: 22 | clean = cleaning.strip('\n').replace('x', letter) 23 | latex_string = latex_string.replace(clean, letter) 24 | 25 | # simple cleanings 26 | for cleaning in cleanings_simple: 27 | latex_string = latex_string.replace(cleaning[0],cleaning[1]) 28 | 29 | return latex_string 30 | 31 | # get Wikidata qid from name using pywikibot 32 | def get_qid_pywikibot(name): 33 | try: 34 | site = pywikibot.Site("en", "wikipedia") 35 | page = pywikibot.Page(site, name) 36 | item = pywikibot.ItemPage.fromPage(page) 37 | qid = item.id 38 | except: 39 | qid = 'N/A' 40 | return qid 41 | 42 | def get_sparql_results(sparql_query_string): 43 | sparql = SPARQLWrapper.SPARQLWrapper("https://query.wikidata.org/sparql") 44 | sparql.setQuery(sparql_query_string) 45 | try: 46 | # stream with the results in XML, see 47 | sparql.setReturnFormat(SPARQLWrapper.JSON) 48 | result = sparql.query().convert() 49 | except: 50 | result = None 51 | return result 52 | 53 | def get_sparql_query_string(name): 54 | 55 | sparql_query_string = """SELECT distinct ?item ?itemLabel ?itemDescription WHERE{ 56 | ?item ?label "%s"@en. 57 | ?article schema:about ?item . 58 | ?article schema:inLanguage "en" . 59 | ?article schema:isPartOf . 60 | SERVICE wikibase:label { bd:serviceParam wikibase:language "en". } 61 | }""" % name 62 | 63 | return sparql_query_string 64 | 65 | def get_qid_sparql(name): 66 | 67 | sparql_query_string = get_sparql_query_string(name) 68 | sparql_results = get_sparql_results(sparql_query_string) 69 | 70 | qid_results = [] 71 | try: 72 | for result in sparql_results['results']['bindings']: 73 | try: 74 | desc = result['itemDescription']['value'] 75 | if desc != 'Wikimedia disambiguation page': 76 | url = result['item']['value'] 77 | qid = url.split("/")[-1] 78 | qid_results.append(qid) 79 | except: 80 | pass 81 | except: 82 | pass 83 | 84 | if len(qid_results) > 0: 85 | qid = qid_results[0] # take first result 86 | else: 87 | qid = 'N/A' 88 | 89 | return qid 90 | 91 | def get_qid_sparql_with_defining_formula(name): 92 | 93 | sparql_query_string = get_sparql_query_string(name) 94 | sparql_results = get_sparql_results(sparql_query_string) 95 | 96 | qid_results = [] 97 | try: 98 | for result in sparql_results['results']['bindings']: 99 | try: 100 | url = result['item']['value'] 101 | qid = url.split("/")[-1] 102 | item = get_Wikidata_item(qid) 103 | try: 104 | defining_formula = item['claims']['P2534'] 105 | except: 106 | defining_formula = 'N/A' 107 | if defining_formula != 'N/A': 108 | qid_results.append(qid) 109 | except: 110 | pass 111 | except: 112 | pass 113 | 114 | if len(qid_results) > 0: 115 | qid = qid_results[0] # take first result 116 | else: 117 | qid = 'N/A' 118 | 119 | return qid 120 | 121 | def get_Wikidata_item(Wikidata_qid): 122 | """Get Wikidata item from qid using https request.""" 123 | 124 | item = requests.get("https://wikidata.org/entity/" + Wikidata_qid) 125 | item = item.json()['entities'][Wikidata_qid] 126 | 127 | return item 128 | 129 | def get_concept_name(Wikidata_item): 130 | """Retrieve concept name from Wikidata item.""" 131 | 132 | name = Wikidata_item['labels']['en']['value'] 133 | 134 | return name 135 | 136 | def get_defining_formula(Wikidata_item): 137 | """Retrieve defining formula from Wikidata item.""" 138 | 139 | defining_formula_property = 'P2534' 140 | defining_formula_object = Wikidata_item['claims'][defining_formula_property] 141 | defining_formula_string = defining_formula_object[0]['mainsnak']['datavalue']['value'] 142 | 143 | # clean LaTeX 144 | defining_formula_string = clean_latex(defining_formula_string) 145 | 146 | return defining_formula_string 147 | 148 | def get_formula_identifiers(Wikidata_item): 149 | """Retrieve formula identifiers from Wikidata item.""" 150 | 151 | # Populate identifier tuples list 152 | identifier_property_tuples = [] 153 | 154 | # Retrieve left-hand side identifier 155 | left_hand_side_symbol_property_key = 'P7235' # 'in defining formula' 156 | identifier_name = Wikidata_item['labels']['en']['value'] 157 | try: 158 | identifier_symbol = Wikidata_item['claims'][left_hand_side_symbol_property_key][0]['mainsnak']['datavalue']['value'] 159 | except: 160 | identifier_symbol = None 161 | 162 | # clean LaTeX 163 | identifier_symbol = clean_latex(identifier_symbol) 164 | 165 | # Add left-hand side identifier to list 166 | identifier_property_tuples.append((identifier_symbol, identifier_name)) 167 | 168 | # Retrieve right-hand side identifiers 169 | for property in ['P527','P4934','P9758']: # 'has part', 'calculated from', 'symbol represents' 170 | try: 171 | properties_object = Wikidata_item['claims'][property] 172 | except: 173 | pass 174 | for identifier_propery in properties_object: 175 | 176 | # get identifier symbol 177 | for property in ['P7235','P416']: 178 | try: 179 | identifier_symbol = identifier_propery['qualifiers'][property][0]['datavalue']['value'] 180 | except: 181 | pass 182 | 183 | # get identifier name 184 | identifier_item_qid = identifier_propery['mainsnak']['datavalue']['value']['id'] 185 | identifier_item = get_Wikidata_item(identifier_item_qid) 186 | identifier_name = identifier_item['labels']['en']['value'] 187 | 188 | # clean LaTeX 189 | identifier_symbol = clean_latex(identifier_symbol) 190 | 191 | identifier_property_tuples.append((identifier_symbol,identifier_name)) 192 | 193 | return identifier_property_tuples -------------------------------------------------------------------------------- /evaluation/module3_identifier_value_generation/Latex2Sympy_transformations.csv: -------------------------------------------------------------------------------- 1 | GoldID;QID;Definining Formula Wikidata;Working LaTeX Input 1;Working LaTeX Input 2;Defining Formula Sympy 1;Defining Formula Sympy 2;Trafo 1;Trafo 2;Trafo 3;Trafo 4;Trafo 5;TODO;;Comment 2 | 310;Q11376;\\boldsymbol{a} = \\frac{\\mathrm{d} \\boldsymbol{v}}{\\mathrm{d} t};a = \frac{d v}{d t};;Derivative(v t);;;\boldsymbol{x} -> x;\mathrm{x} -> x;;;;; 3 | 311;Q186300;\boldsymbol{\alpha} = \frac{\mathrm{d} \boldsymbol{\omega}}{\mathrm{d} t};;;;;;;;;;;; 4 | 312;Q834020;\omega = 2 \pi f;\omega = 2 \pi f;;2*pi*f;;;;;;;;; 5 | 313;Q161254;\mathbf{L} = \mathbf{r} \times \mathbf{p};L = R \times p;;L;R*p;r -> R;\mathbf{x} -> x;;;;;; 6 | 314;Q161635;\boldsymbol{\omega} = \frac{\mathrm{d} \varphi}{\mathrm{d} t} \boldsymbol{u};\omega = \frac{\mathrm{d} \varphi}{\mathrm{d} t} u;;omega;u*Derivative(varphi, t);\boldsymbol{x} -> x;\mathrm{x} -> x;;;;;; 7 | 315;Q2945123;\sum_{i=1}^n m_i(\mathbf{r}_i - \mathbf{R}) = 0;;;;;;;;;;;;Not sure what to do. 8 | 316;Q2248131;a_c = \frac {v^2} {r};a_{b} = \frac{a^2}{b};;a_b = a**2/b;;;;;;;;; 9 | 317;Q172881;\vec{F} = - \frac{mv^2 \hat{r}}{r};-;;-;;\vec{x} -> x ;\hat{x} -> x;;;;;; 10 | 318;Q843905;C=\pi\cdot{d}=2\pi\cdot{r};C=\pi\cdot{d};C = 2 \pi\cdot{r};\pi\cdot{d};;;;;;;;;\cdot{r} works perfect {r} for all other alphabets. 11 | 319;Q11382;E_{tot,1} = E_{tot,2};a_{tot,1};a_{tot,2};;;;;;;;;;"Does not work for ""E_""." 12 | 320;Q2305665;p_{tot,1} = p_{tot,2};p_{tot,1} = p_{tot,2};;;;;;;;;;;Only shows right hand side for any equation. 13 | 321;Q1127660;\zeta = \frac{c}{2\sqrt{mk}};-;-;-;;;;;;;;;\zeta -> zeta and \sqrt{mk} -> sqrt(k*m) works well. 14 | 322;Q272621;i\hbar\frac{\partial \Psi}{\partial t} = (c\hat \boldsymbol \alpha \cdot \hat \boldsymbol p + mc^2\hat \beta)\Psi;-;-;-;;\Psi -> Psi;\alpha -> alpha;\beta -> beta;;;x;;\hbar, \partial, \hat, does not work. \alpha{x} -> alpha*x, an unexpected output. 15 | 323;Q16853908;i\gamma^a e_a^\mu D_\mu \Psi - m \Psi = 0;-;-;-;;;;;;;;;\gamma^a -> gamma**a, a^\mu -> a**mu, m \Psi -> Psi*m works well. 16 | 324;Q891408;U = \frac{1}{2}k \Delta x^2;\frac{1}{2}k \Delta x^2;;1*1/2*k*Delta*x**2;;;;;;;;; 17 | 325;Q849919;\vec{F} = q(\vec{E} + \vec{v} \times \vec{B});-;-;-;;\vec{x} -> x;;;;;;;"only ""v \times B"" works well. (a + b \times c) does not work." 18 | 326;Q103438301;\vec{F}_e = \frac{q_1 q_2}{4 \pi \epsilon_{0} r^2} \hat{r};-;-;-;;\hat{x} -> x;;;;;;;\pi -> pi, q_1 -> q_1, q_2 -> q_2, \epsilon_{0} -> epsilon_0 works. r^2 does not work. 19 | 327;Q103439852;E^2 = p^2c^2 + m^2c^4;-;-;-;;;;;;;;;E^2 (e^2 -> exp(2)), c^2, c^4 (but C^4 works well) does not work. p^2, m^2 works well. 20 | 328;Q166530;v_{\text{e}} = \sqrt{\frac{2GM}{r}} = \sqrt{2gr};-;-;-;;\text{x} -> x;;;;;;;\frac{2ab}{d}-> (2*a*b)/d (\frac{2ab}{c} does not work but \frac{2ab}{C} works well), \sqrt{2ab} -> sqrt(2*a*b) works. 21 | 329;Q875744;\frac{\mathrm{d}}{\mathrm{d} t}\left(\frac{\partial L}{\partial \dot{q}_{j}}\right)=\frac{\partial L}{\partial q_{j}};-;-;-;;;;;;;;;\mathrm{d} t -> dt, q_{j} -> q_j works well. {q}_{j} -> q does not work. 22 | 330;Q11402;\mathbf{F} = \frac{\mathrm{d} \mathbf{p}}{\mathrm{d} t};;;;;;;;;;;;\mathrm{d} t -> dt, q_{j} -> q_j, \left( \frac{x}{y}\right) -> x/y works well. \dot{q} and \dot q, {q}_{j} -> q does not work. 23 | 331;Q1068463;p^\mu=\begin{matrix}p_0 \\ p_1 \\ p_2 \\ p_3 \end{matrix} = \begin{matrix}E/c \\ p_x \\ p_y \\ p_z \end{matrix} = \begin{matrix}E/c \\ \vec p \end{matrix};-;-;-;;;;;;;;;p^mu -> p**mu works well. I also refer . 24 | 332;Q1322540;\mathbf{U} \equiv \frac{d \mathbf{R}}{d \tau};U \equiv \frac{d R}{d \tau};;Eq(U, Derivative(R, tau));;\mathbf{x} -> x;\mathbf{x} -> x;;;;;;a \equiv b -> Eq(a, b), \tau -> tau works well. 25 | 333;Q140028;v(t)=-gt+v_{0};v = -gt+v_{0};;#NAME?;;v(t) -> v_t;;;;;;; 26 | 334;Q11652;f = \frac{1}{T};f = \frac{1}{T};;1*1/T;;;;;;;;; 27 | 335;Q82580;F_{\mathrm{kf}} = \mu_{\mathrm{kf}} F_\mathrm{N};;;;;\mathrm{x} -> x;;;;;;;\mathrm works only for \mathrm{d}. 28 | 336;Q219207;(t,\mathbf x) \mapsto (t+s,\mathsf R\mathbf x + \mathbf vt + \mathbf y);-;-;-;;;;;;;;;nothing works. 29 | 337;Q6806305;p_i = \frac{\partial L}{\partial \dot{q}_i};-;-;-;;;;;;;;;"only ""p_i"" works. If we remove \partial and \dot, then meaning of the equation significantly changes." 30 | 338;Q30006;\vec{g}=-\frac{Gm_\oplus}{{R_\oplus}^2} \hat{r};;;;;;;;;;;;nothing works. 31 | 339;Q11412;\vec{F}_g = - \frac{G m_1 m_2}{r^2} \hat{r};;;;;;;;;;;; 32 | 340;Q1544012;U=-\frac{GMm}{r};-;-;-;;;;;;;;;For -\frac{GMm}{r} substituting -\frac{abC}{d} works. 33 | 341;Q660488;\mathcal{H}\left(\mathbf{q},\mathbf{p},t\right) = \mathbf{p}\cdot\dot{\mathbf{q}} - \mathcal{L}\left(\mathbf{q},\dot{\mathbf{q}},t\right);-;-;-;;\mathcal{x} -> x;\mathbf{x} -> x;;;;;;nothing works. 34 | 342;Q1060137;\frac{\partial S}{\partial t}=-H;\frac{d S}{d t};#NAME?;Derivative(S, t);;\partial -> d;;;;;;; 35 | 343;Q170282;F= k X;F= k X;;X*k;;;;;;;x;; 36 | 344;Q497332;\vec \zeta(t) = \frac {\mathrm {d}}{\mathrm {d}t}\vec{\alpha}(t)=\dot{\vec\alpha}(t);-;-;-;;;;;;;;;\zeta(t)-> t*zeta does not work. 37 | 345;Q46276;T = \frac{1}{2} m v^2;T = \frac{1}{2} m v^2;;1*1/2*m*v**2;;;;;;;;; 38 | 346;Q103687426;\mathcal{L} = T-V;T-V;;T - V;;\mathcal{x} -> x;;;;;;; 39 | 347;Q599404;\gamma = \frac{1}{\sqrt{1 - v^2/c^2}};\gamma = \frac{1}{\sqrt{1 - V^2/C^2}};;1*1/(sqrt(1 - V**2/C**2));;;;;;;;;"Change the case of ""v"" and ""c""." 40 | 348;Q172137;\mathbf{F} = q(\mathbf{E} + \mathbf{v} \times \mathbf{B});-;-;-;;\vec{x} -> x;;;;;;; 41 | 349;Q217255;t' = \gamma \left( t - \frac{v x}{c^2} \right) x' = \gamma \left( x - v t \right);t' = \gamma \left( T - \frac{V X}{C^2} \right);x' = \gamma \left( X - V T \right);gamma*(T - V*X/C**2);gamma*(-T*V + X);;;;;;;; 42 | 350;Q35875;E = m c^2;E = m C^2;;C**2*m;;;;;;;;;"Change the case of ""c"" to ""C""." 43 | 351;Q6421317;Z_{\mathrm{m}} = Z_{\mathrm{a}} A^2;Z_m = Z_a A^2;;Z_m;A**2*Z_a;\mathrm{x} -> x;;;;;;; 44 | 352;Q165618;J_{\mathrm{Q}} = \int r_{\mathrm{Q}}^{2} \mathrm{d} m;J_Q = \int x_{y}^2 \mathrm{d} m;;J_Q;Integral(x_y**2, x);;;;;;x;;\mathrm{d} m supress in the final output. 45 | 353;Q41273;\mathbf{p} = m \mathbf{v};p = m v;;m*v;;\mathbf{x} -> x;;;;;;; 46 | 354;Q2397319;\vec{F} = m \cdot \vec{a};F = m \cdot a;;a*m;;\vec{x} -> x;;;;;;; 47 | 355;Q3235565;\mathbf{F}_{12}=-\mathbf{F}_{21};F_{12} = - F_{21};;F_{12}=-F_{21};;\mathbf{x} -> x;;;;;;; 48 | 356;Q170475;z(t) = A \mathrm{e}^{-\zeta \omega_0 t} \sin \left( \sqrt{1 - \zeta^2} \omega_0 t + \varphi \right);-;-;-;-;;;;;;;;\zeta -> zeta, \omega -> omega, \varphi -> varphi works well. 49 | 357;Q20702;\frac{\mathrm{d}^2\theta}{\mathrm{d}t^2} + \frac{g}{l}\sin\theta = 0;\frac{\mathrm{d}^2\theta}{\mathrm{d}t^2};\frac{g}{l}\sin \theta;(d**2*theta)/dt**2;g*sin(theta)/l;;;;;;;;Both terms of left hand side together could not produce correct SymPy output. 50 | 358;Q25342;P = \frac{\mathrm{d} E}{\mathrm{d} t};P = \frac{\mathrm{d} e}{\mathrm{d} t};;Derivative(E, t);;;;;;;;;"Change the case of ""E"" to ""e""." 51 | 359;Q240105;\omega = \frac{d\phi}{dt} = \frac{v_\perp}{r};\omega = \frac{d\phi}{dt};\omega = \frac{V}{R};Derivative(phi, t);V/R;;;;;;;;"Change the case of ""v"" and ""r"" to ""V"" and ""R""." 52 | 360;Q11663629;E_0 = m_0 c_0^2;e_0 = m_0 \times C_0^2;;C_0**2*m_0;;E -> e;c -> C;;;;;;"Change the case of ""E"" to ""e"" and ""c"" to ""C""." 53 | 361;Q96941619;(m_\mathrm{rest})c^2=\sqrt{E_\mathrm{total}^2-(|\mathbf{p}|c)^2};(m)C^2=\sqrt{E^2-(|p|C)^2};;C**2*m;;E -> Energy (expected);;;;;;;"Due to ""E"" term convert to ""exponential""." 54 | 362;Q676622;\mathit{Ro} = \frac{v}{2 l \omega_{\mathrm{E}} \sin{\varphi}};R_o = \frac{v}{2 l \omega_{e} \sin{\varphi}};;R_o;v/((2*l*omega_e*sin(varphi)));\mathit{x} -> x;xo -> x_o;\mathrm{x} -> {x};;;x;; 55 | 363;Q3711325;v = s / t;v = s / t;;s/t;;;;;;;;; 56 | 364;Q2111;c=f\lambda;C=f\lambda;;f*lambda;;c -> C;;;;;;; 57 | 365;Q12507;x^2+y^2+z^2=r^2;x^2+y^2+z^2 = R^2;;x**2 + y**2 + z**2;R**2;r -> R;;;;;;; 58 | 366;Q3299367;\psi(x,t) = A \cos (k x - \omega t+\varphi);A \cos (k x - \omega t+\varphi);;A*cos(k*x - omega*t + varphi);;;;;;;;;\psi(x,t) does not work. Anything in the form of f(x) does not work. 59 | 367;Q824561;F_d = 6\pi\,\mu\,R\,V;F_d = 6 \pi \mu R V;;F_d;6*pi*R*V*mu;;;;;;;; 60 | 368;Q206175;\sigma = \frac{F}{A};\sigma = \frac{d F}{d A};;sigma;Derivative(F, A);;;;;;;; 61 | 369;Q2822927;\alpha = \frac{dv_{\perp}}{dt};\alpha = \frac{d v}{d t};;alpha;Derivative(v, t);;;;;;;; 62 | 370;Q103715245;v = \omega r;v = \omega R;;v;R*omega;r -> R;;;;;;; 63 | 371;Q48103;T = \mathbf{M} \cdot \mathbf{e}_{\mathrm{Q}};T = M \cdot X_{Q};;T;M*X_Q;E -> X;\mathbf{x} -> x;\mathrm{x} -> x;;;;; 64 | 372;Q376742;\mathbf{s} = \mathbf{v}t;s = v t;;s ;t*v;\mathbf{x} -> x;;;;;;; 65 | 373;Q11465;\mathbf{v} = \frac{\mathrm{d} \mathbf{r}}{\mathrm{d} t};v = \frac{\mathrm{d} R}{\mathrm{d} t};;v;\frac{\mathrm{d} R}{\mathrm{d} t};r -> R;;;;;;; 66 | 374;Q192510;\sigma = 1/\lambda;\sigma = 1/\lambda;;sigma ;1*1/lambda;;;;;;;; 67 | 375;Q42213;A = \int_{\Gamma} \mathbf{F} \cdot \mathrm{d} \mathbf{r};A = F \cdot \mathrm{d} R;;A ;F*dR;remove \int_{x} ;;;;;;; 68 | -------------------------------------------------------------------------------- /evaluation/module_workflow/unit_test_module_workflow_latex2sympy_generated(0).csv: -------------------------------------------------------------------------------- 1 | ;GoldID;QID;Name;Working;Formula;Identifiers;Properties;Formula unit;Identifier units;Formula sympy;Identifiers sympy;Sympy rhs;Numeric 2 | 0;310;Q11376;acceleration;;a = \frac{d v}{d t};[('acceleration', 'a', 'm s^-2'), ('velocity', 'v', 'm s^-1'), ('duration', 't', 's')];P7235;m s^-2;;Derivative(v, t);(a, v, t);Subs(Derivative(1, t), t, 5);- 3 | 1;311;Q186300;angular acceleration;;\boldsymbol{\alpha} = \frac{d \boldsymbol{\omega}}{d t};[('angular acceleration', '\\boldsymbol{\\alpha}', 's^-2'), ('angular velocity', '\\boldsymbol{\\omega}', 's^-1'), ('duration', 't', 's')];P7235;s^-2;;N/A;(\boldsymbol{\alpha}, \boldsymbol{\omega}, t);N/A;- 4 | 2;312;Q834020;angular frequency;yes;\omega = 2 \pi f;[('angular frequency', '\\omega', 's^-1'), ('frequency', 'f', 's^-1')];P7235;s^-1;;2*pi*f;(\omega, f);6*pi;x 5 | 3;313;Q161254;angular momentum;;L = R* p;[('angular momentum', 'L', 'm^2 kg s^-1'), ('position vector', 'r', 'm'), ('momentum', 'p', 'm kg s^-1')];P7235;m^2 kg s^-1;;R*p;(L, r, p);3*R;- 6 | 4;314;Q161635;angular velocity;;\boldsymbol{\omega} = \frac{d \varphi}{d t} u;N/A;P7235;s^-1;;N/A;N/A;N/A;- 7 | 5;315;Q2945123;center of mass;;\sum_{i=1}^n m_i(r_i - R) = 0;N/A;P4934, P7235;N/A;;N/A;N/A;N/A;- 8 | 6;316;Q2248131;centripetal acceleration;;a_C= \fraC{v^2} {r};[('velocity', 'v', 'm s^-1'), ('radius', 'r', 'm'), ('centripetal acceleration', 'a_c', 'm s^-2')];P4934, P7235;m s^-2;;N/A;(v, r, a_c);N/A;- 9 | 7;317;Q172881;centripetal force;;F = - \frac{mv^2 r}{r};[('force', 'F', 'm kg s^-2'), ('mass', 'm', 'kg'), ('velocity', 'v', 'm s^-1'), ('radius', 'r', 'm')];P527;m kg s^-2;;N/A;(F, m, v, r);N/A;- 10 | 8;318;Q843905;circumference;;C=\pi*{d}=2\pi*{r};[('diameter', 'd', 'm'), ('circumference', 'C', 'm'), ('radius', 'r', 'm')];P4934;m;;N/A;(d, C, r);N/A;- 11 | 9;319;Q11382;conservation of energy;;E_{tot,1} = E_{tot,2};[('energy', 'E', 'm^2 kg s^-2')];P527;N/A;;N/A;E;N/A;- 12 | 10;320;Q2305665;conservation of momentum;;p_{tot,1} = p_{tot,2};[];;N/A;;p_{tot,2};N/A;N/A;- 13 | 11;321;Q1127660;damping;;\zeta = \frac{c}{2\sqrt{mk}};N/A;P527;N/A;;N/A;N/A;N/A;- 14 | 12;322;Q272621;Dirac equation;;i\hbar\frac{d \Psi}{d t} = (c\hat \boldsymbol \alpha * \hat \boldsymbol p + mc^2\hat \beta)\Psi;N/A;P527;N/A;;N/A;N/A;N/A;- 15 | 13;323;Q16853908;Dirac equation in curved spacetime;;i\gamma^a e_a^\mu D_\mu \Psi - m \Psi = 0;N/A;P527;N/A;;E*gamma**a*i;N/A;E*gamma**a*i;- 16 | 14;324;Q891408;elastic energy;;U = \frac{1}{2}k \Delta x^2;[('spring constant', 'k', 'kg s^-2'), ('linear strain', '\\Delta x', '1'), ('elastic energy', 'U', 'm^2 kg s^-2')];P4934, P7235;m^2 kg s^-2;;1*1/2*k*Delta*x**2;(k, \Delta, x, U);N/A;- 17 | 15;325;Q849919;electromagnetic force;;F = q(e+ v * B);N/A;P527;N/A;;q*(B*v + E);N/A;q*(B*v + E);- 18 | 16;326;Q103438301;electrostatic force;;F_e = \frac{q_1 q_2}{4 \pi \epsilon_{0} r^2} r;[('force', 'F', 'm kg s^-2'), ('electric charge', 'q', 's A'), ('distance', 'r', 'm'), ('vacuum permittivity', 'r', 'm^-3 kg^-1 s^4 A^2')];P527;N/A;;N/A;(F, q, r, r);N/A;- 19 | 17;327;Q103439852;energy-momentum relation;;E^2 = p^2c^2 + m^2c^4;[('energy', 'E', 'm^2 kg s^-2'), ('momentum', 'p', 'm kg s^-1'), ('mass', 'm', 'kg'), ('speed of light', 'c', 'm s^-1')];P527;N/A;;N/A;(E, p, m, c);N/A;- 20 | 18;328;Q166530;escape velocity;;v_{\text{e}} = \sqrt{\frac{2GM}{r}} = \sqrt{2gr};N/A;P4934;m s^-1;;N/A;N/A;N/A;- 21 | 19;329;Q875744;Euler–Lagrange equation;;\frac{d}{d t}\left(\frac{d L}{d \dot{q}_{j}}\right)=\frac{d L}{d q_{j}};N/A;P527;N/A;;N/A;N/A;N/A;- 22 | 20;330;Q11402;force;;F = \frac{d p}{d t};[('momentum', 'p', 'm kg s^-1'), ('duration', 't', 's'), ('mass', 'm', 'kg'), ('acceleration', 'a', 'm s^-2'), ('force', 'F', 'm kg s^-2')];P4934, P7235;m kg s^-2;;Derivative(p, t);(p, t, m, a, F);Subs(Derivative(p, t), t, 2);- 23 | 21;331;Q1068463;four-momentum;;p^\mu=\begin{matrix}p_0 \\ p_1 \\ p_2 \\ p_3 \end{matrix} = \begin{matrix}E/C\\ p_x \\ p_y \\ p_z \end{matrix} = \begin{matrix}E/C\\ \veCp \end{matrix};[('momentum', 'p', 'm kg s^-1'), ('energy', 'E', 'm^2 kg s^-2'), ('speed of light', 'c', 'm s^-1')];P527;N/A;;N/A;(p, E, c);N/A;- 24 | 22;332;Q1322540;four-velocity;;U \equiv \frac{d R}{d \tau};N/A;P527;N/A;;Eq(U, Derivative(R, tau));N/A;Derivative(R, tau);- 25 | 23;333;Q140028;free fall;;v(t)=-gt+v_{0};N/A;P527;N/A;;#NAME?;N/A;#NAME?;- 26 | 24;334;Q11652;frequency;yes;f = \frac{1}{T};[('frequency', 'f', 's^-1'), ('period', 'T', 's')];P7235;s^-1;;1*1/T;(f, T);NUMBER;x 27 | 25;335;Q82580;friction;;F_{\mathrm{kf}} = \mu_{\mathrm{kf}} F_N;N/A;P4934, P7235;m kg s^-2;;N/A;N/A;N/A;- 28 | 26;336;Q219207;Galilean transformation;;(t,\mathbf x) \mapsto (t+s,\mathsf R\mathbf x + \mathbf vt + \mathbf y);N/A;P527;N/A;;N/A;N/A;N/A;- 29 | 27;337;Q6806305;generalized momentum;;p_i = \frac{d L}{d \dot{q}_i};N/A;P4934, P7235;N/A;;N/A;N/A;N/A;- 30 | 28;338;Q30006;gravitational acceleration;;g=-\frac{GM}{{R}^2} r;N/A;P527, P4934, P7235;m s^-2;;-G*M/R**2;N/A;-G*M/R**2;- 31 | 29;339;Q11412;gravity;;F_g = - \frac{G m_1 m_2}{r^2} r;N/A;P527;m kg s^-2;;N/A;N/A;N/A;- 32 | 30;340;Q1544012;gravitational potential;;U=-\frac{GMm}{r};N/A;P527;m^2 s^-2;;N/A;N/A;N/A;- 33 | 31;341;Q660488;Hamiltonian operator;;H\left(q,p,t\right) = p*\dot{q} - L\left(q,\dot{q},t\right);[];;N/A;;N/A;N/A;N/A;- 34 | 32;342;Q1060137;Hamilton–Jacobi equation;;X^n + Y^n = Z^n;N/A;P4934;N/A;;Z**n;N/A;Z**n;- 35 | 33;343;Q170282;Hooke's law;yes;F= k X;[('force', 'F', 'm kg s^-2'), ('spring constant', 'k', 'kg s^-2'), ('linear strain', 'X', '1')];P527;m kg s^-2;;X*k;(F, k, X);NUMBER;x 36 | 34;344;Q497332;jerk;;j = \frac{d a}{d t};[('acceleration', 'a', 'm s^-2'), ('duration', 't', 's'), ('jerk', 'j', 'm s^-3')];P4934, P7235;m s^-3;;Derivative(a, t);(a, t, j);Subs(Derivative(a, t), t, 9);- 37 | 35;345;Q46276;kinetic energy;yes;T = \frac{1}{2} m v^2;[('kinetic energy', 'T', 'm^2 kg s^-2'), ('mass', 'm', 'kg'), ('speed', 'v', 'm s^-1')];P7235;m^2 kg s^-2;;1*1/2*m*v**2;(T, m, v);NUMBER;x 38 | 36;346;Q103687426;Lagrangian operator;;L = T-V;N/A;P527;N/A;;T - V;N/A;T - V;- 39 | 37;347;Q599404;Lorentz factor;;\gamma = \frac{1}{\sqrt{1 - v^2/c^2}};[('velocity', 'v', 'm s^-1'), ('speed of light', 'c', 'm s^-1')];P527;N/A;;N/A;(v, c);N/A;- 40 | 38;348;Q172137;Lorentz force;;F = q(e+ v * B);N/A;P4934, P7235;m kg s^-2;;q*(B*v + E);N/A;q*(B*v + E);- 41 | 39;349;Q217255;Lorentz transformation;;t' = \gamma \left( t - \frac{v x}{c^2} \right), x' = \gamma \left( x - v t \right);N/A;P527;N/A;;t;N/A;t;- 42 | 40;350;Q35875;mass–energy equivalence;;e= m c^2;[('energy', 'E', 'm^2 kg s^-2'), ('mass', 'm', 'kg'), ('speed of light', 'c', 'm s^-1')];P7235;N/A;;m;(E, m, c);NUMBER;x 43 | 41;351;Q6421317;mechanical impedance;;Z_{m} = Z_{a} A^2;[('acoustic impedance', 'Z_{a}', 'm^-4 kg s^-1'), ('area', 'A', 'm^2'), ('mechanical impedance', 'Z_{m}', 'kg s^-1')];P4934, P7235;kg s^-1;;A**2*Z_a;(Z_{a}, A, Z_{m});49*Z_a;- 44 | 42;352;Q165618;moment of inertia;;J_{Q} = \int r_{Q}^{2} d m;[('radial distance', 'r_{Q}', 'm'), ('mass', 'm', 'kg'), ('moment of inertia', 'J_{Q}', 'm^2 kg')];P4934, P7235;m^2 kg;;N/A;(r_{Q}, m, J_{Q});N/A;- 45 | 43;353;Q41273;momentum;yes;p = m v;[('momentum', 'p', 'm kg s^-1'), ('mass', 'm', 'kg'), ('velocity', 'v', 'm s^-1')];P7235;m kg s^-1;;m*v;(p, m, v);NUMBER;x 46 | 44;354;Q2397319;Newton's second law of motion for constant mass;;F = m * a;N/A;P527, P7235;N/A;;a*m;N/A;a*m;- 47 | 45;355;Q3235565;Newton's third law of motion;;F_{12}=-F_{21};[('force', 'F', 'm kg s^-2')];P527;N/A;;-F_{21};F;N/A;- 48 | 46;356;Q170475;oscillation;;z(t) = A e^{-\zeta \omega_0 t} \sin \left( \sqrt{1 - \zeta^2} \omega_0 t + \varphi \right);N/A;P527;N/A;;A*exp(-omega_0*t*zeta)*sin(omega_0*t*sqrt(1 - zeta**2) + varphi);N/A;exp(-omega_0*t*zeta)*sin(omega_0*t*sqrt(1 - zeta**2) + varphi);- 49 | 47;357;Q20702;pendulum;;\frac{d^2\theta}{dt^2} + \frac{g}{l}\sin\theta = 0;N/A;P527;N/A;;0;N/A;NUMBER;x 50 | 48;358;Q25342;power;;P = \frac{d E}{d t};[('energy', 'E', 'm^2 kg s^-2'), ('duration', 't', 's'), ('power', 'P', 'm^2 kg s^-3')];P4934, P7235;m^2 kg s^-3;;N/A;(E, t, P);N/A;- 51 | 49;359;Q240105;radial velocity;;\omega = \frac{d\phi}{dt} = \frac{v_\perp}{r};N/A;P527;m s^-1;;N/A;N/A;N/A;- 52 | 50;360;Q11663629;rest energy;;E_0 = m_0 c_0^2;[('rest mass', 'm_0', 'kg'), ('speed of light', 'c_0', 'm s^-1'), ('rest energy', 'E_0', 'm^2 kg s^-2')];P4934, P7235;m^2 kg s^-2;;N/A;(m_0, c_0, E_0);N/A;- 53 | 51;361;Q96941619;rest mass;;(m_\mathrm{rest})c^2=\sqrt{E_\mathrm{total}^2-(|p|c)^2};[('mass', 'm', 'kg'), ('speed of light', 'c', 'm s^-1'), ('energy', 'E', 'm^2 kg s^-2'), ('momentum', 'p', 'm kg s^-1')];P4934;kg;;N/A;(m, c, E, p);N/A;- 54 | 52;362;Q676622;Rossby number;;\mathit{Ro} = \frac{v}{2 l \omega_{E} \sin{\varphi}};N/A;P4934, P7235;1;;N/A;N/A;N/A;- 55 | 53;363;Q3711325;speed;yes;v = s / t;[('speed', 'v', 'm s^-1'), ('distance', 's', 'm'), ('duration', 't', 's')];P7235;m s^-1;;s/t;(v, s, t);NUMBER;x 56 | 54;364;Q2111;speed of light;;c=f\lambda;[('frequency', 'f', 's^-1'), ('wavelength', '\\lambda', 'm')];P4934;m s^-1;;N/A;(f, \lambda);N/A;- 57 | 55;365;Q12507;sphere;;x^2+y^2+z^2=r^2;N/A;P527;N/A;;N/A;N/A;N/A;- 58 | 56;366;Q3299367;Spherical pendulum;;\psi(x,t) = A \cos (k x - \omega t+\varphi);N/A;P527;N/A;;N/A;N/A;N/A;- 59 | 57;367;Q824561;Stokes' law;;F_d = 6\pi\,\mu\,R\,V;N/A;P527;N/A;;N/A;N/A;N/A;- 60 | 58;368;Q206175;stress;;\sigma = \frac{dF}{dA};N/A;P527, P4934;m^-1 kg s^-2;;Derivative(F, A);N/A;Subs(Derivative(F, A), A, 4);- 61 | 59;369;Q2822927;stress;;\sigma = \frac{dF}{dA};N/A;P527, P4934;m^-1 kg s^-2;;Derivative(F, A);N/A;Subs(Derivative(F, A), A, 8);- 62 | 60;370;Q103715245;tangential velocity;;v = \omega r;[('velocity', 'v', 'm s^-1'), ('angular velocity', 'v', 's^-1'), ('radius', 'r', 'm')];P527;N/A;;omega;(v, v, r);omega;- 63 | 61;371;Q48103;torque;;T = M * e_{Q};N/A;P7235;m^2 kg s^-2;;E*M;N/A;E*M;- 64 | 62;372;Q376742;uniform motion;;s = vt;N/A;P527;N/A;;t*v;N/A;t*v;- 65 | 63;373;Q11465;velocity;;v = \frac{d r}{d t};N/A;P527, P7235;m s^-1;;N/A;N/A;N/A;- 66 | 64;374;Q192510;wavenumber;;\sigma = 1/\lambda;[('wavenumber', '\\sigma', 'm^-1'), ('wavelength', '\\lambda', 'm')];P7235;m^-1;;1*1/lambda;(\sigma, \lambda);1*1/lambda;- 67 | 65;375;Q42213;work;;A = \int_{\Gamma} F * d r;[('work', 'A', 'm^2 kg s^-2'), ('force', 'F', 'm kg s^-2'), ('position vector', 'r', 'm')];P7235;m^2 kg s^-2;;N/A;(A, F, r);N/A;- 68 | -------------------------------------------------------------------------------- /module1_formula_and_identifier_retrieval.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import string 3 | import requests 4 | import pywikibot 5 | import SPARQLWrapper 6 | 7 | # load cleanings 8 | cleanings_simple_identifier = [] 9 | cleanings_simple_formula = [] 10 | with open('latex_cleanings_simple_identifier.csv') as f: 11 | for row in csv.reader(f): 12 | cleanings_simple_identifier.append((row[0],row[1])) 13 | with open('latex_cleanings_simple_formula.csv') as f: 14 | for row in csv.reader(f): 15 | cleanings_simple_formula.append((row[0],row[1])) 16 | with open('latex_cleanings_argument.txt') as f: 17 | cleanings_argument = f.readlines() 18 | 19 | def derivative_to_division(latex_string): 20 | deriv_start_str = '\\frac{d' 21 | deriv_middle_str = '}{d' 22 | deriv_end_str = '}' 23 | if deriv_start_str in latex_string and deriv_end_str in latex_string: 24 | start_idx = latex_string.find(deriv_start_str) + len(deriv_start_str) 25 | deriv_content = latex_string[start_idx:] 26 | deriv_content = deriv_content.replace(deriv_middle_str,'/') 27 | try: 28 | end_idx = deriv_content.find(deriv_end_str)[0] 29 | except: 30 | end_idx = deriv_content.find(deriv_end_str) 31 | deriv_content = deriv_content[0:end_idx].strip('}') 32 | if '=' in latex_string: 33 | equal_sign_idx = latex_string.find('=') 34 | latex_string = latex_string[:equal_sign_idx+1] + deriv_content 35 | else: 36 | latex_string = deriv_content 37 | return latex_string 38 | 39 | def clean_latex(latex_string,mode): 40 | """Clean LaTeX formula for converter.""" 41 | 42 | # argument cleanings 43 | alphabet = list(string.ascii_lowercase) + list(string.ascii_uppercase) 44 | for cleaning in cleanings_argument: 45 | for letter in alphabet: 46 | clean = cleaning.strip('\n').replace('x', letter) 47 | latex_string = latex_string.replace(clean, letter) 48 | 49 | # derivative cleanings 50 | #latex_string = derivative_to_division(latex_string) 51 | 52 | # simple cleanings 53 | if mode == 'identifier': 54 | cleanings = cleanings_simple_identifier 55 | elif mode == 'formula': 56 | cleanings = cleanings_simple_formula 57 | for cleaning in cleanings: 58 | latex_string = latex_string.replace(cleaning[0],cleaning[1]) 59 | 60 | return latex_string 61 | 62 | # get Wikidata qid from name using pywikibot 63 | def get_qid_pywikibot(name): 64 | try: 65 | site = pywikibot.Site("en", "wikipedia") 66 | page = pywikibot.Page(site, name) 67 | item = pywikibot.ItemPage.fromPage(page) 68 | qid = item.id 69 | except: 70 | qid = 'N/A' 71 | return qid 72 | 73 | def get_sparql_results(sparql_query_string): 74 | sparql = SPARQLWrapper.SPARQLWrapper("https://query.wikidata.org/sparql") 75 | sparql.setQuery(sparql_query_string) 76 | try: 77 | # stream with the results in XML, see 78 | sparql.setReturnFormat(SPARQLWrapper.JSON) 79 | result = sparql.query().convert() 80 | except: 81 | result = None 82 | return result 83 | 84 | def get_sparql_query_string(name): 85 | 86 | sparql_query_string = """SELECT distinct ?item ?itemLabel ?itemDescription WHERE{ 87 | ?item ?label "%s"@en. 88 | ?article schema:about ?item . 89 | ?article schema:inLanguage "en" . 90 | ?article schema:isPartOf . 91 | SERVICE wikibase:label { bd:serviceParam wikibase:language "en". } 92 | }""" % name 93 | 94 | return sparql_query_string 95 | 96 | def get_qid_sparql(name): 97 | 98 | sparql_query_string = get_sparql_query_string(name) 99 | sparql_results = get_sparql_results(sparql_query_string) 100 | 101 | qid_results = [] 102 | try: 103 | for result in sparql_results['results']['bindings']: 104 | try: 105 | desc = result['itemDescription']['value'] 106 | if desc != 'Wikimedia disambiguation page': 107 | url = result['item']['value'] 108 | qid = url.split("/")[-1] 109 | qid_results.append(qid) 110 | except: 111 | pass 112 | except: 113 | pass 114 | 115 | if len(qid_results) > 0: 116 | qid = qid_results[0] # take first result 117 | else: 118 | qid = 'N/A' 119 | 120 | return qid 121 | 122 | def get_qid_sparql_with_defining_formula(name): 123 | 124 | sparql_query_string = get_sparql_query_string(name) 125 | sparql_results = get_sparql_results(sparql_query_string) 126 | 127 | qid_results = [] 128 | try: 129 | for result in sparql_results['results']['bindings']: 130 | try: 131 | url = result['item']['value'] 132 | qid = url.split("/")[-1] 133 | item = get_Wikidata_item(qid) 134 | try: 135 | defining_formula = item['claims']['P2534'] 136 | except: 137 | defining_formula = 'N/A' 138 | if defining_formula != 'N/A': 139 | qid_results.append(qid) 140 | except: 141 | pass 142 | except: 143 | pass 144 | 145 | if len(qid_results) > 0: 146 | qid = qid_results[0] # take first result 147 | else: 148 | qid = 'N/A' 149 | 150 | return qid 151 | 152 | def get_Wikidata_item(Wikidata_qid): 153 | """Get Wikidata item from qid using https request.""" 154 | 155 | item = requests.get("https://wikidata.org/entity/" + Wikidata_qid) 156 | item = item.json()['entities'][Wikidata_qid] 157 | 158 | return item 159 | 160 | def get_concept_name(Wikidata_item): 161 | """Retrieve concept name from Wikidata item.""" 162 | 163 | name = Wikidata_item['labels']['en']['value'] 164 | 165 | return name 166 | 167 | def get_defining_formula(Wikidata_item): 168 | """Retrieve defining formula from Wikidata item.""" 169 | 170 | defining_formula_property = 'P2534' 171 | defining_formula_object = Wikidata_item['claims'][defining_formula_property] 172 | defining_formula_string = defining_formula_object[0]['mainsnak']['datavalue']['value'] 173 | 174 | # clean LaTeX 175 | defining_formula_string = clean_latex(defining_formula_string,mode='formula') 176 | 177 | return defining_formula_string 178 | 179 | def convert_unit_dimensions(ISQ_dimensions): 180 | """Convert unit from ISQ dimensions to SI units.""" 181 | 182 | unit_dimensions = ISQ_dimensions 183 | # Translate into SI standard form 184 | # mathsf_content = re.search(r'mathsf{(.*?)}', identifier_unit_dimension) 185 | for expression in ['\mathsf', '{', '}']: 186 | unit_dimensions = unit_dimensions.replace(expression, '') 187 | 188 | # Map Symbol for dimension to SI unit symbol 189 | # See https://en.wikipedia.org/wiki/International_System_of_Quantities 190 | mapping = {'L': 'm', 'M': 'kg', 'T': 's', 'I': 'A', '\Theta': 'K', 'N': 'mol', 'J': 'cd'} 191 | for k,v in mapping.items(): 192 | try: 193 | unit_dimensions = unit_dimensions.replace(k,v) 194 | except: 195 | pass 196 | SI_dimensions = unit_dimensions 197 | 198 | return SI_dimensions 199 | 200 | def get_formula_unit_dimension(Wikidata_item): 201 | """Get ISQ unit dimensions of formula.""" 202 | 203 | formula_unit_dimensions = Wikidata_item['claims']['P4020'][0]['mainsnak']['datavalue']['value'] # 'ISQ dimension' 204 | print('Formula_unit_available: ',formula_unit_dimensions) 205 | # Convert from ISQ to SI 206 | formula_unit_dimensions = convert_unit_dimensions(formula_unit_dimensions) 207 | 208 | return formula_unit_dimensions 209 | 210 | def get_identifier_properties(Wikidata_item): 211 | 212 | # Populate identifier properties list of (name, symbol, unit) triples 213 | identifier_properties = [] 214 | 215 | # Get identifier property claims 216 | property_claims = {} 217 | for identifier_property_key in ['P527', 'P4934', 'P7235']: # 'has part', 'calculated from', 'in defining formula' 218 | try: 219 | property_claim = Wikidata_item['claims'][identifier_property_key] 220 | property_claims[identifier_property_key] = property_claim 221 | except: 222 | pass 223 | 224 | # Exploit identifier property claims 225 | for property_claim in property_claims.items(): 226 | 227 | try: 228 | 229 | P = property_claim[0] 230 | print('Identifier properties in: ',P) 231 | for identifier in property_claim[1]: 232 | 233 | # Identifier QID 234 | identifier_qid = '' 235 | if P == 'P7235': # 'in defining formula' 236 | sub_prop = 'P9758' # 'symbol represents' 237 | try: 238 | identifier_qid = identifier['qualifiers'][sub_prop][0]['datavalue']['value']['id'] 239 | except: 240 | pass 241 | elif P in ['P527', 'P4934']: # 'has part', 'calculated from' 242 | try: 243 | identifier_qid = identifier['mainsnak']['datavalue']['value']['id'] 244 | except: 245 | pass 246 | if identifier_qid == '': 247 | identifier_qid = Wikidata_item['id'] 248 | 249 | # Identifier item 250 | identifier_item = get_Wikidata_item(identifier_qid) 251 | 252 | # Identifier name 253 | identifier_name = get_concept_name(identifier_item) 254 | 255 | # Identifier symbol 256 | if P == 'P7235': # 'in defining formula' 257 | identifier_symbol = identifier['mainsnak']['datavalue']['value'] 258 | elif P in ['P527', 'P4934']: # 'has part', 'calculated from' 259 | for property in ['P416', 'P7973', 'P2534', 'P7235']: 260 | # 'quantity symbol (string)', 'quantity symbol (LaTeX)', 'defining formula', 'in defining formula' 261 | try: 262 | identifier_symbol = identifier['qualifiers'][property][0]['datavalue']['value'] 263 | except: 264 | pass 265 | # Clean LaTeX 266 | identifier_symbol = clean_latex(identifier_symbol,mode='identifier') 267 | 268 | # Identifier unit 269 | identifier_unit_property = identifier_item['claims']['P4020'] # 'ISQ dimension' 270 | identifier_unit_dimension = identifier_unit_property[0]['mainsnak']['datavalue']['value'] 271 | # Convert from ISQ to SI 272 | identifier_unit = convert_unit_dimensions(identifier_unit_dimension) 273 | 274 | print('Identifier property: ',(identifier_name,identifier_symbol,identifier_unit)) 275 | identifier_properties.append((identifier_name,identifier_symbol,identifier_unit)) 276 | 277 | except: 278 | pass 279 | 280 | return identifier_properties -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /evaluation/Applied_questions.csv: -------------------------------------------------------------------------------- 1 | GoldID;QID;Name;Application;Example question 2 | 310;Q11376;acceleration;Cheetah;A cheetah can run from rest to 26 m/s in 3 seconds. How much acceleration gains the cheetah? 3 | 311;Q186300;angular acceleration;flywheel;A flywheel attains an angular speed of 18.4 rad s^-1 from rest state in 2.3 s. What is the magnitude of the angular acceleration gained by the flywheel? 4 | 312;Q834020;angular frequency;simple harmonic accelerator;A simple harmonic oscillator has a frequency of 0.5 s^-1. What is the angular frequency of the oscillator? 5 | 313;Q161254;angular momentum;point mass;A point mass of 0.25 kg is in horizontal uniform circular motion. The magnitude of its tangential velocity is 2 m s^-1. The point mass is located at the distance of 0.1 m from the center of rotation. What is the magnitude of its angular momentum? 6 | 314;Q161635;angular velocity;location on the earth's surface;A city is located at the earth's equator. The earth completes a full revolution (2 pi rad) in about 24 h (86400 s). What is the magnitude of angular velocity of the city? 7 | 315;Q2945123;center of mass;mass;Two masses of 5 kg and 1 kg are located at a distance of 6 m from each other. Find the center of mass of the system. Assume that the heavier mass is located at the origin and the line joining the two masses as the x-axis. 8 | 316;Q2248131;centripetal acceleration;child;A child of mass 20 kg is sitting on the edge of a merry-go-round that has a radius of 3 m. The child is revolving with a uniform tangential velocity of magnitude 5 m s^-1. What is the magnitude of the centripetal acceleration of the child? 9 | 317;Q172881;centripetal force;jet plane;How much centripetal force is exerted on a 15000 kg jet plane that negotiates a 4000 m radius horizontal circular loop at 120 m s^-1? 10 | 318;Q843905;circumference;value of pi;If the circumference of a circle is 16.3 m and its diameter is 5.2 m. What is the approximate value of pi? 11 | 319;Q11382;conservation of energy;marble;A marble of 5 kg drops from a height of 10 m from the ground, where the magnitude of the acceleration due to gravity is 9.8 m s^-2. What is the magnitude of the velocity of the marble just before hitting the ground? 12 | 320;Q2305665;conservation of momentum;mass;Two masses of 0.6 kg and 0.2 kg respectively are approaching each other with a velocity of 3 m s^-1 along a horizontal and frictionless surface. They have a head-on, completely inelastic collision. After the collision, they stick to each other and move together. What is the magnitude of their combined velocity? 13 | 321;Q1127660;damping;damping system;A damping system has a damping factor of 0.8 along with a spring constant of 2 N m^-1 and mass 8 kg. What is the magnitude of its damping coefficient? 14 | 322;Q272621;Dirac equation;Not applicable;Not applicable 15 | 323;Q16853908;Dirac equation in curved spacetime;Not applicable;Not applicable 16 | 324;Q891408;elastic energy;mass;A mass of 5 kg with spring constant 2 N m^-1 in an ideal spring-mass system is in rest state. A mass is displaced by a force from its equilibrium position and the spring-mass system gains an elastic energy of 0.38 J. By how much distance from the equilibrium position has the mass been displaced? 17 | 325;Q849919;electromagnetic force;charged particle;A charged particle q enters in a perpendicular direction with velocity 1.7 \times 10^4 m s^-1 to the mutually perpendicular electric field and magnetic field of magnitude 4 N m^-1 and 1.4 T, respectively. If the electromagnetic force experienced by the charged particle is approximately 0.05 N, what is the magnitude of the particle's charge? 18 | 326;Q103438301;electrostatic force;Electron;Two electrons (charge 1.6 \times 10^-19 C) are separated from each other in the vacuum at a distance of 1 \times 10^-8 m. What is the magnitude of the electrostatic force of repulsion between the two electrons? Assume electric constant 1/4 \pi epsilon_0 = 9 \times 10^9 N m^2 C^-2. 19 | 327;Q103439852;energy-momentum relation;Proton;A proton moving at a speed of v = 0.86 c and therefore has a relativistic momentum of p = 1580 MeV/c. The proton has a rest energy of 938 MeV. What is the magnitude of its total relativistic energy? 20 | 328;Q166530;escape velocity;Jupiter;Jupiter's equatorial radius is 7.1492 \times 10^7 m and escape velocity is 0.595 \times 10^5 m s^-1. What is the value of the mass of jupiter? Assume the universal gravitational constant being 6.67430 \times 10^-11 m^3 kg^-1 s^-2. 21 | 329;Q875744;Euler–Lagrange equation;Not applicable;Not applicable 22 | 330;Q11402;force;mass;A force of 10 N is acting on a mass of 5 kg. How much acceleration is resulting? 23 | 331;Q1068463;four-momentum;Not applicable;Not applicable 24 | 332;Q1322540;four-velocity;Not applicable;Not applicable 25 | 333;Q140028;free fall;Lead ball;A lead ball is thrown from the top of a tower with a velocity of 2 m s^-1. What is its magnitude of the velocity after 4 s? The value of acceleration due to gravity is 9.8 m s^-2. Neglect the air resistance. 26 | 334;Q11652;frequency;Tuning fork;For a tuning fork in Clang mode of vibration, the time period is 0.0004 s. What is the frequency? 27 | 335;Q82580;friction;crate;A force of 300 N is needed to move a 850 N crate across a level surface with constant velocity. What is the value of the coefficient of the kinetic friction? 28 | 336;Q219207;Galilean transformation;Not applicable;Not applicable 29 | 337;Q6806305;generalized momentum;Not applicable;Not applicable 30 | 338;Q30006;gravitational acceleration;Mercury;The mass of mercury is 3.3011 \times 10^23 kg with an equatorial radius of 2439.7 \times 10^3 m. What is the value of acceleration due to gravity on the surface of mercury? Assume n universal gravitational constant of 6.67430 \times 10^-11 m^3 kg^-1 s^-2). 31 | 339;Q11412;gravity;mass;Two masses of 3 kg and 5 kg are separated from each other at a distance of 20 m. What is the magnitude of the gravitational force of attraction? Assume a universal gravitational constant of 6.67430 \times 10^-11 m^3 kg^-1 s^-2. 32 | 340;Q1544012;gravitational potential;Mercury;The planet mercury revolves around the sun in an elliptical orbit. At its perihelion position, it is located at a distance of 4.6 \times 10^3 m. The mass of mercury is 3.285 × 10^23 kg and the sun weighs 1.989 × 10^30 kg. What is the magnitude of the gravitational potential due to the sun on mercury at perihelion position? Assume a universal gravitational constant of 6.67430 \times 10^-11 m^3 kg^-1 s^-2. 33 | 341;Q660488;Hamiltonian operator;Not applicable;Not applicable 34 | 342;Q1060137;Hamilton–Jacobi equation;Not applicable;Not applicable 35 | 343;Q170282;Hooke's law;spring scale;A spring scale in a shop stretches 3.2 cm from its equilibrium position, when 19.2 N of raw material is weighted. What is the value of the spring constant? 36 | 344;Q497332;jerk;mass;A mass experiences a change of acceleration of 8 m s^-2 in a time interval of 3.2 s. What is the magnitude of jerk exerted on the mass? 37 | 345;Q46276;kinetic energy;bullet;A bullet fired from a gun has a mass of 0.004 kg and a constant velocity of 120 m s^-1. What is the kinetic energy of the bullet? 38 | 346;Q103687426;Lagrangian operator;spring-mass system;An ideal spring-mass system is in the state of motion. It has a kinetic energy of 15.0 J and potential energy of 5.6 J. What is the magnitude of Langrangian operator? 39 | 347;Q599404;Lorentz factor;proton;A proton is moving at a speed of v = 0.86c. What is the value of the Lorentz factor? 40 | 348;Q172137;Lorentz force;blood flowmeter;In a velocity selector of a blood flowmeter, ions move to the right at 7 \times 10^3 m s^-1. The electric field is 400 V m^-1. What is the magnitude of the magnetic field? 41 | 349;Q217255;Lorentz transformation;Not applicable;Not applicable 42 | 350;Q35875;mass–energy equivalence;electron;The mass of an electron is 9.1 \times 10^-31 kg. How much is the rest energy of an electron in electron-volts? 43 | 351;Q6421317;mechanical impedance;Not applicable;Not applicable 44 | 352;Q165618;moment of inertia;flywheel;A flywheel is a solid, uniform disk of mass 3 kg and radius 10 \times 10^-2 m. What is moment of inertia of the flywheel? 45 | 353;Q41273;momentum;space rocket;During takeoff, a rocket has mass (including fuel) of 2 \times 10^6 kg, and its velocity is 140 m s^-1. What is the momentum of the rocket? 46 | 354;Q2397319;Newton's second law of motion for constant mass;block;The mass of a block is 20 kg. If the mass is pulled vertically upwards with a force of 400 N. What is the acceleration of the block? Assume no other forces like, for example, gravitation are present. 47 | 355;Q3235565;Newton's third law of motion;polar bear;A 200 kg polar bear is standing still near a frozen lake in Svalbard, Norway. The acceleration due to gravity at that place is approximately 9.8 m \times s^-2. What is the magnitude of the force with which the polar bear pulls on the earth? 48 | 356;Q170475;oscillation;Not applicable;Not applicable 49 | 357;Q20702;pendulum;Not applicable;Not applicable 50 | 358;Q25342;power;mascular power;A man runs up the stairs from ground level to the top of the building. He spends 4.2 \times 10^5 J energy to reach the top in 600 s. How much muscular power is utilised by the man? 51 | 359;Q240105;radial velocity;centrifuge ;The radius of a centrifuge is 15 \times 10^-2 m and it spins at 270 pi rad s^-1. What is the radial velocity of an object moving at the outer edge? 52 | 360;Q11663629;rest energy;electron;The mass of an electron is 9.109 \times 10^-31 kg. The speed of light is 2.998 \times 10^8 m s^-1. What is the magnitude of the rest energy associated with the electron? 53 | 361;Q96941619;rest mass;neutron;The rest energy associated with the neutron is 1.5054277 \times 10^-10 J. The speed of light is 2.998 \times 10^8 m s^-1. What is the rest mass the of neutron? 54 | 362;Q676622;Rossby number;Earth; Earth speed at equator, characteristic length, earth's angular frequency, and latitude is 10 ms^-1, 6 \times 10^6 m, 7.292 \times 10^-5 rad s^-1, and 45 degrees. What is the value of Rossby's number for the earth? 55 | 363;Q3711325;speed;car;A car drives with a speed of 3 m/s. How much distance can it cover in 1 s? 56 | 364;Q2111;speed of light;gamma rays;In an electromagnetic spectrum, gamma rays have a wavelength of 1 \times 10^-18 m and frequency of 3 \times 10^26 s^-1. What is the speed of light? 57 | 365;Q12507;sphere;sphere;A sphere has its center at coordinate origin. The cartesian coordinates of an arbitrary point on its surface are (1,2,3). What is the radius of the sphere? 58 | 366;Q3299367;Spherical pendulum;spherical pendulum;The amplitude, wavenumber, angular velocity, and phase for a spherical pendulum is 0.5 m, pi/3 rad m^-1, 2*pi/3 rad s^-1, and pi/2, respectively. What is the linear strain in the spherical pendulum at the location 2 m and time 5 s? 59 | 367;Q824561;Stokes' law;pollen grain;During an experiment, lightweight pollen grains are dropped inside a clear glass cylinder, and their motion is observed with a microscope. A radius 15 \times 10^-6 m pollen grain is measured to fall at a rate of 4.7 \times 10^-2 m s^-1. The dynamic viscosity of the air inside the glass cylinder is 1.849 \times 10^-5 kg m^-1 s^-1. What is the magnitude of the frictional force exerted on the pollen grains? 60 | 368;Q206175;stress;femur bone;A cross-section area of the bone in the femur of a 784 N person is 5.1 \times 10^-4 m^-2. What is the net stress on the femur? 61 | 369;Q2822927;tangential acceleration;sprocket-wheel;A tip of a racing sprocket-wheel changes its magnitude of tangential velocity from rest to 30 m s^-1 in 1.2 s. What is the tangential acceleration of the sprocket-wheel tip? 62 | 370;Q103715245;tangential velocity;blade of wind turbine;The tip of a large wind turbine blade is at distance of 40 m from its rotation center axis. The angular velocity of the blade is 2 rad s^-1. What is the magnitude of tangential velocity? 63 | 371;Q48103;torque;door of bank vault;To open a giant bank vault door, a minimum torque of 35 N m is needed when a tangential force F is applied at a distance 1.3 m from the axis of rotation. What is the magnitude of the force F? 64 | 372;Q376742;uniform motion;yacht;A yacht makes short rectilinear trips between two nearby islands with a constant velocity of magnitude 14.4 m s^-1 in 372 s. What is the displacement of the yacht in one way trip? 65 | 373;Q11465;velocity;athlete;An athelete sprints in a straight line for 100 m in 9.2 s. What is his velocity? 66 | 374;Q192510;wavenumber;microwave oven;A household microwave oven operates at a wavelength of 12.24 \times 10^-2 m. What is the value of the corresponding wavenumber? 67 | 375;Q42213;work;sled;A dog tugs a sled 5 m on a snowy track at a constant speed with a force of 300 N. How much work does the dog do? 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PhysWikiQuiz 2 | 3 | We present [**PhysWikiQuiz**](https://physwikiquiz.wmflabs.org), a Physics Exam Question Generation and Test System. The system can generate physics questions from [Wikidata](https://wikidata.org) items, given a Formula Concept Name or QID (e.g., 'speed' or 'Q11376') user input. Each question contains comprehensive details of the involved physical quantities, and randomly generated numerical values. In a consecutive step, a student can input an answer. The system then checks the correctness of the user input in terms of quantity value and unit respectively. In the last stage, the system finally generates a correct explanation of the solution, including its calculation path. 4 | 5 | [**PhysWikiQuiz**](https://physwikiquiz.wmflabs.org) is a web-based system, implemented with Flask, a micro web-framework written in Python. The required metadata for formulae is retrieved from [Wikidata](https://wikidata.org) by means of [SPARQL](https://www.w3.org/TR/rdf-sparql-query/) queries or [Pywikibot](https://www.mediawiki.org/wiki/Manual:Pywikibot). 6 | The system is hosted by Wikimedia at [https://physwikiquiz.wmflabs.org](https://physwikiquiz.wmflabs.org). 7 | 8 | ## Motivation 9 | 10 | Examination is the essential part in every student’s academic life. A significant portion of any physics examination is based upon formula based numerical examples. This system accelerates the process of examination preparation by generating large numbers of novel questions from the open and continuously evolving semantic knowledge-base [Wikidata](https://wikidata.org). The question generation helps students to have study material to train for exams and teachers, tutors, or professors to automatically prepare exam sheets, which significantly reduces their time efforts. Moreover, generating different questions and values for each student separately makes student cheating more difficult. 11 | 12 | ## Demo Examples 13 | 14 | Demo of example formula concept **"speed"**: 15 | 16 | ![Demo speed](images/PhysWikiQuiz_demo_speed.gif) 17 | 18 | Demo of example formula concept **"acceleration"**: 19 | 20 | ![Demo acceleration](images/PhysWikiQuiz_demo_acceleration.gif) 21 | 22 | You can quickly check the system hosted at https://physwikiquiz.wmflabs.org. 23 | 24 | You also find a video demonstration of the PhysWikiQuiz system and its evaluation [here](https://purl.org/physwikiquiz) (you will be redirected to YouTube). 25 | 26 | ## System Workflow 27 | 28 | PhysWikiQuiz employs the open access semantic knowledge-base [Wikidata](https://wikidata.org) to retrieve Wikimedia community-curated physics formulae with identifier properties and units using their concept name as input. A given formula is then rearranged, i.e., solved for each occurring identifier by a Computer Algebra System (CAS) to create several question families. For each rearrangement, random identifier values are generated (in a specified range). Finally, the system compares the student's answer input to a CAS computed solution for both value and unit separately and generates an explanation text. 29 | 30 | **The following diagram illustrates the fundamental workflow of the system.** 31 | 32 | ![Fundamental Workflow](images/PhysWikiQuiz-Workflow_white.png) 33 | 34 | In module 1, formula and identifier data is retrieved from [Wikidata](https://wikidata.org). In module 2, the formula is rearranged using the python CAS [Sympy](https://www.sympy.org). In module 3, random values are generated for the formula identifiers. In module 4, the question text is generated from the available information. In module 5, the student's answer is compared to the system's solution. Finally, module 6 generates an explanation text for the student. In case some step or module can not be successfully executed, the user is notified, e.g., 'No Wikidata item with formula found'. 35 | 36 | **Let us learn the workflow of the system with the example formula concept "acceleration"**. 37 | 38 | The following figure shows an example expression tree for "acceleration". Below each of the identifier symbols a, v, and t, information about its properties (Wikidata item name and QID, unit dimension) is displayed. 39 | 40 | ![Workflow diagram for acceleration](images/PhysWikiQuiz_workflow_acceleration.png) 41 | 42 | We now describe the module tasks using the example. 43 | 44 | **Module 1** retrieves **formula and identifier information** from Wikidata properties. 45 | 46 | In our example case: 47 | * 'defining formula' (P2534): 'a=\frac{dv}{dt}' 48 | * 'in defining formula' (P7235): 'a' 49 | * 'has part' (P527) or 'calculated from' (P4934): 50 | * 'velocity' (Q11465) 51 | * 'duration' (Q2199864) 52 | 53 | **Module 2** generates **various possible rearrangements** of the retrieved formula. 54 | 55 | In our example case: 56 | * 57 | * 58 | * 59 | 60 | **Module 3** generates **random numerical values** for the unknown identifier variables and performs the required mathematical operations in order to calculate the **numerical value of the desired identifier**. 61 | 62 | In our example case: 63 | For the two available formula rearrangements , , and , the system calculates the respective right-hand side identifier values by performing the required multiplication or division operation. The result is later compared to the user input to check its correctness.​ 64 | 65 | **Module 4** generates a **well-structured question in natural language** by using the available names, symbols, and values for the occurring formula identifiers. 66 | 67 | In our example case: 68 | "What is the acceleration a, given velocity v = 4 m s^-1, duration t = 5 s?" 69 | 70 | **Module 5 checks the solution value and unit** entered by the user and displays a correctness assessment. 71 | 72 | In our example case: 73 | If the user entered "4/5 m s^-2" value and unit are correct. If it was "4 m s^-2", only the unit is correct. If it was "4/5 m", only the value is correct. 74 | 75 | **Module 6 generates an explanation text** with the formula (including source) and a calculation path for the student's understanding. 76 | 77 | In our example case: 78 | "Solution from www.wikidata.org/wiki/Q11376 formula a = v/t with 4/5 m s^-2 = 4 m s^-1 / 5 s ." 79 | 80 | In the following, you can see the **final stage of the system**, after finishing all tasks: 81 | ![final stage](images/PhysWikiQuiz_acceleration.png) 82 | 83 | ## Number of Questions 84 | 85 | In principle, PhysWikiQuiz does not depend on formula rearrangements and the workflow would be complete without them. However, they enhance the availability of additional question variations. In the case of our example "speed", using Sympy rearrangements also the other variables "distance" and "durations" can be queried, providing additional concept questions. 86 | 87 | The number of questions generated by >>PhysWikiQuiz<< can be calculated as N_generated = N_identifiers * R_values ^ (N_identifiers - 1) 88 | with 89 | N_identifiers: Number of identifiers in Formula Concept, 90 | R_values = 10: Range for random identifier value generation (here from 1 to 10). 91 | 92 | This leads to the following table: 93 | 94 | | N_identifiers | N_generated | 95 | | ------------- |---------------| 96 | | 1 | 1 | 97 | | 2 | 20 | 98 | | 3 | 300 | 99 | | 4 | 4000 | 100 | | 5 | 50000 | 101 | | 6 | 600000 | 102 | | 7 | 7000000 | 103 | | 8 | 80000000 | 104 | | 9 | 900000000 | 105 | | 10 | 10000000000 | 106 | 107 | It is evident that for large formulae, PhysWikiQuiz can generate a tremendous amount of question variations. But even for a small formula with 2 identifiers there are already 20 possibilities. On average, the formulae in the testset contain 3 identifiers, which leads to 300 potential questions per Formula Concept. Without rearrangements the possibilities need to be divided by the number of formula identifiers. 108 | 109 | ## Evaluation on Benchmark 110 | 111 | We made a detailed PhysWikiQuiz system evaluation at each individual stage of its workflow. We carried out unit tests for the different modules and an integration test to assess the overall performance on a Formula Concept benchmark dataset. 112 | 113 | ### Benchmark Dataset 114 | 115 | The open-access platform [MathMLben](https://mathmlben.wmflabs.org) stores and displays a benchmark of semantically annotated mathematical formulae. They were extracted from [Wikipedia](https://en.wikipedia.org), the [arXiv](https://arxiv.org) and the Digital Library of Mathematical Functions [DLMF](https://dlmf.nist.gov) and augmented by Wikidata markup. The benchmark can be used to evaluate a variety of MathIR tasks, such as the automatic conversion between different CAS or Mathematical Question Answering [MathQA](https://mathqa.wmflabs.org). In our PhysWikiQuiz evaluation, we employ a selection of 66 formulae (GoldID 310-375) from the MathMLben goldstandard. The Formula Concepts were extracted from Wikipedia articles using the formula and identifier annotation recommendation system [AnnoMathTeX](https://annomathtex.wmflabs.org). 116 | 117 | The following table shows the PhysWikiQuiz system performance on the selected Formula Concept benchmark (MathMLben GoldID 310-375). For each concept, e.g., 'speed', the results of the different modules is displayed. At the bottom the total percentage of the available functionality is provided. 118 | 119 | [Unit Test Module Workflow](images/unit_test_module_workflow.png) 120 | 121 | All result tables and evaluation logs can be found [here](evaluation/module_workflow). 122 | 123 | ## Installation Dependencies 124 | 125 | A deployed version of the system is available online, hosted by Wikimedia at https://physwikiquiz.wmflabs.org. Installing locally on your machine, the system mainly depends on the following python packages (for a full list see `requirements.txt`). 126 | 127 | ### Flask 128 | The web framework Flask `version 0.12.2` is used as web framework middleware used as an interface between the frontend and the backend. 129 | ``` 130 | pip3 install Flask 131 | ``` 132 | ### Requests 133 | Requests `version 2.26.0` is an HTTP library designed to make HTTP requests simpler and more human-friendly. 134 | ``` 135 | pip3 install requests 136 | ``` 137 | ### Pywikibot 138 | Pywikibot `version 5.6.0`is used to extract the formula concept data from Wikidata: [https://tools.wmflabs.org/pywikibot](https://tools.wmflabs.org/pywikibot) 139 | ``` 140 | pip3 install pywikibot 141 | ``` 142 | ### SPARQLWrapper 143 | SPARQLWrapper `version 1.8.2` is a simple Python wrapper around a [SPARQL](https://www.w3.org/TR/sparql11-overview) service to remotely execute queries. It helps to create the query invokation and convert the result into a more manageable format. 144 | ``` 145 | pip3 install sparqlwrapper 146 | ``` 147 | ### Sympy 148 | The Computer Algebra System (CAS) Sympy `version 1.7.1` is used for the calculation module to get result values given a retrieved formula and inputs for the variables. 149 | ``` 150 | apt-get install python3-sympy 151 | ``` 152 | 153 | ### Latex2Sympy 154 | LaTeX2Sympy `version 1.6.2` is used to convert variants of LaTeX formula strings to a Sympy equivalent form. 155 | 156 | 1) ANTLR is used to generate the parser: 157 | ``` 158 | sudo apt-get install antlr4 159 | ``` 160 | 2) Download latex2sympy from [https://github.com/augustt198/latex2sympy](https://github.com/augustt198/latex2sympy) 161 | 162 | ### **To clone or download the repository** 163 | ``` 164 | git clone https://github.com/ag-gipp/PhysWikiQuiz.git 165 | ``` 166 | 167 | ## PhysWikiQuiz API for question generation 168 | Example query using Wikidata item name ('speed'): 169 | ``` 170 | https://physwikiquiz.wmflabs.org/api/v1?name=speed 171 | ``` 172 | Example query using Wikidata item QID ('Q124164'): 173 | ``` 174 | https://physwikiquiz.wmflabs.org/api/v1?qid=Q124164 175 | ``` 176 | 177 | ## API references 178 | 179 | * [Wikidata](https://wikidata.org): A SPARQL query to the [Wikidata Query Services API](https://query.wikidata.org) retrieves lists or properties of [Wikidata items](https://en.wikipedia.org/wiki/Wikidata#Items) 180 | * [VMEXT](https://vmext-demo.formulasearchengine.com/swagger-ui.html): LaTeX to SymPy formula conversion is done via the 'LaCASt' translator 181 | 182 | 186 | 187 | ## License 188 | 189 | This project is licensed under the Apache License 2.0. 190 | 191 | ## Acknowledgments 192 | 193 | We thank the Wikimedia foundation for [hosting](https://physwikiquiz.wmflabs.org) our web-based system. 194 | -------------------------------------------------------------------------------- /evaluation/module1_formula_and_identifier_retrieval/Identifier_Unit_Wikidata_Properties_evaluation.csv: -------------------------------------------------------------------------------- 1 | GoldID;Identifier symbol;Identifier name;Formula QID;Identifier QID;ISQ dimension (P4020);recommended unit of measurement (P8111);numeric value (P1181) 2 | 310;a;acceleration;Q11376;Q11376;\mathsf{L} \mathsf{T}^{-2};; 3 | 310;v;velocity;Q11376;Q11465;;; 4 | 310;t;duration;Q11376;Q2199864;;; 5 | 311;\alpha;angular acceleration;;;;; 6 | 311;\omega;angular velocity;;;;; 7 | 311;t;duration;;;;; 8 | 312;\omega;angular frequency;;;;; 9 | 312;\pi;\pi;;;;; 10 | 312;f;frequency;;;;; 11 | 313;L;angular momentum;;;;; 12 | 313;r;position vector;;;;; 13 | 313;\times;cross product;;;;; 14 | 313;p;momentum;;;;; 15 | 314;\omega;angular velocity;;;;; 16 | 314;\varphi;angular displacement;;;;; 17 | 314;t;duration;;;;; 18 | 314;u;unit vector;;;;; 19 | 315;i;nominal number;;;;; 20 | 315;m;mass;;;;; 21 | 315;r;position vector;;;;; 22 | 315;R;center of mass;;;;; 23 | 316;a;centripetal acceleration;;;;; 24 | 316;v;velocity;;;;; 25 | 316;r;radius of curvature;;;;; 26 | 317;F;force;;;;; 27 | 317;m;mass;;;;; 28 | 317;v;velocity;;;;; 29 | 317;r;unit vector;;;;; 30 | 317;r;radius;;;;; 31 | 318;C;circumference;;;;; 32 | 318;\pi;pi;;;;; 33 | 318;d;diameter;;;;; 34 | 318;r;radius;;;;; 35 | 319;E;energy;;;;; 36 | 319;energy;E;;;;; 37 | 320;p;momentum;;;;; 38 | 320;momentum;p;;;;; 39 | 321;\zeta;damping;;;;; 40 | 321;c;constant;;;;; 41 | 321;m;mass;;;;; 42 | 321;k;spring constant;;;;; 43 | 321;damping;\zeta;;;;; 44 | 321;constant;c;;;;; 45 | 321;mass;m;;;;; 46 | 321;spring constant;k;;;;; 47 | 322;i;imaginary unit;;;;; 48 | 322;\hbar;reduced Planck constant;;;;; 49 | 322;\partial;partial derivative symbol;;;;; 50 | 322;\Psi;wave function;;;;; 51 | 322;t;duration;;;;; 52 | 322;c;speed of light;;;;; 53 | 322;p;momentum;;;;; 54 | 322;m;mass;;;;; 55 | 322;imaginary unit;i;;;;; 56 | 322;reduced Planck constant;\hbar;;;;; 57 | 322;partial derivative symbol;\partial;;;;; 58 | 322;wave function;\Psi;;;;; 59 | 322;duration;t;;;;; 60 | 322;speed of light;c;;;;; 61 | 322;momentum;p;;;;; 62 | 322;mass;m;;;;; 63 | 323;i;imaginary unit;;;;; 64 | 323;\gamma;Lorentz factor;;;;; 65 | 323;e;tetrad formalism;;;;; 66 | 323;D;differential operator;;;;; 67 | 323;\Psi;wave function;;;;; 68 | 323;m;mass;;;;; 69 | 323;imaginary unit;i;;;;; 70 | 323;Lorentz factor;\gamma;;;;; 71 | 323;tetrad formalism;e;;;;; 72 | 323;differential operator;D;;;;; 73 | 323;wave function;\Psi;;;;; 74 | 323;mass;m;;;;; 75 | 324;U;elastic energy;;;;; 76 | 324;k;spring constant;;;;; 77 | 324;x;linear strain;;;;; 78 | 324;elastic energy;U;;;;; 79 | 324;spring constant;k;;;;; 80 | 324;linear strain;x;;;;; 81 | 325;F;Lorentz force;;;;; 82 | 325;q;electric charge;;;;; 83 | 325;E;electric field;;;;; 84 | 325;v;velocity;;;;; 85 | 325;B;magnetic field;;;;; 86 | 325;Lorentz force;F;;;;; 87 | 325;electric charge;q;;;;; 88 | 325;electric field;E;;;;; 89 | 325;velocity;v;;;;; 90 | 325;magnetic field;B;;;;; 91 | 326;F;force;;;;; 92 | 326;q;electric charge;;;;; 93 | 326;pi;pi;;;;; 94 | 326;\epsilon;vacuum permittivity;;;;; 95 | 326;r;distance;;;;; 96 | 326;r;unit vector;;;;; 97 | 326;force;F;;;;; 98 | 326;electric charge;q;;;;; 99 | 326;pi;pi;;;;; 100 | 326;vacuum permittivity;\epsilon;;;;; 101 | 326;distance;r;;;;; 102 | 326;unit vector;r;;;;; 103 | 327;E;energy;;;;; 104 | 327;p;momentum;;;;; 105 | 327;c;speed of light;;;;; 106 | 327;m;mass;;;;; 107 | 327;energy;E;;;;; 108 | 327;momentum;p;;;;; 109 | 327;speed of light;c;;;;; 110 | 327;mass;m;;;;; 111 | 328;v;escape velocity;;;;; 112 | 328;e;gravitational constant;;;;; 113 | 328;G;gravitational mass;;;;; 114 | 328;M;distance;;;;; 115 | 328;r;gravitational acceleration;;;;; 116 | 328;g;v;;;;; 117 | 328;escape velocity;e;;;;; 118 | 328;gravitational constant;G;;;;; 119 | 328;gravitational mass;M;;;;; 120 | 328;distance;r;;;;; 121 | 328;gravitational acceleration;g;;;;; 122 | 329;t;duration;;;;; 123 | 329;\partial;partial derivative symbol;;;;; 124 | 329;L;Lagrangian;;;;; 125 | 329;q;generalized velocity;;;;; 126 | 329;q;generalized coordinate;;;;; 127 | 329;duration;t;;;;; 128 | 329;partial derivative symbol;\partial;;;;; 129 | 329;Lagrangian;L;;;;; 130 | 329;generalized velocity;q;;;;; 131 | 329;generalized coordinate;q;;;;; 132 | 330;F;force;;;;; 133 | 330;p;momentum;;;;; 134 | 330;t;duration;;;;; 135 | 330;force;F;;;;; 136 | 330;momentum;p;;;;; 137 | 330;duration;t;;;;; 138 | 331;p;momentum;;;;; 139 | 331;E;energy;;;;; 140 | 331;c;speed of light;;;;; 141 | 331;momentum;p;;;;; 142 | 331;energy;E;;;;; 143 | 331;speed of light;c;;;;; 144 | 332;U;velocity;;;;; 145 | 332;R;location;;;;; 146 | 332;\tau;proper time;;;;; 147 | 332;velocity;U;;;;; 148 | 332;location;R;;;;; 149 | 332;proper time;\tau;;;;; 150 | 333;v;velocity;;;;; 151 | 333;g;gravitational acceleration;;;;; 152 | 333;t;duration;;;;; 153 | 333;velocity;v;;;;; 154 | 333;gravitational acceleration;g;;;;; 155 | 333;duration;t;;;;; 156 | 334;f;frequency;;;;; 157 | 334;T;period;;;;; 158 | 334;frequency;f;;;;; 159 | 334;period;T;;;;; 160 | 335;F;friction;;;;; 161 | 335;\mu;coefficient of friction;;;;; 162 | 335;F;normal force;;;;; 163 | 335;friction;F;;;;; 164 | 335;coefficient of friction;\mu;;;;; 165 | 335;normal force;F;;;;; 166 | 336;t;duration;;;;; 167 | 336;x;location;;;;; 168 | 336;s;delay;;;;; 169 | 336;R;rotation matrix;;;;; 170 | 336;v;velocity;;;;; 171 | 336;y;displacement;;;;; 172 | 336;duration;t;;;;; 173 | 336;location;x;;;;; 174 | 336;delay;s;;;;; 175 | 336;rotation matrix;R;;;;; 176 | 336;velocity;v;;;;; 177 | 336;displacement;y;;;;; 178 | 337;p;generalized momentum;;;;; 179 | 337;\partial;partial derivative symbol;;;;; 180 | 337;L;Lagrange function;;;;; 181 | 337;q;generalized velocity;;;;; 182 | 337;generalized momentum;p;;;;; 183 | 337;partial derivative symbol;\partial;;;;; 184 | 337;Lagrange function;L;;;;; 185 | 337;generalized velocity;q;;;;; 186 | 338;g;gravitational acceleration;;;;; 187 | 338;G;gravitational constant;;;;; 188 | 338;M;mass;;;;; 189 | 338;R;radius;;;;; 190 | 338;r;position vector;;;;; 191 | 338;gravitational acceleration;g;;;;; 192 | 338;gravitational constant;G;;;;; 193 | 338;mass;M;;;;; 194 | 338;radius;R;;;;; 195 | 338;position vector;r;;;;; 196 | 339;F;force;;;;; 197 | 339;G;gravitational constant;;;;; 198 | 339;m;mass;;;;; 199 | 339;r;distance;;;;; 200 | 339;force;F;;;;; 201 | 339;gravitational constant;G;;;;; 202 | 339;mass;m;;;;; 203 | 339;distance;r;;;;; 204 | 340;U;potential;;;;; 205 | 340;G;gravitational constant;;;;; 206 | 340;M;mass;;;;; 207 | 340;m;mass;;;;; 208 | 340;r;distance;;;;; 209 | 340;potential;U;;;;; 210 | 340;gravitational constant;G;;;;; 211 | 340;mass;M;;;;; 212 | 340;mass;m;;;;; 213 | 340;distance;r;;;;; 214 | 341;H;Hamiltonian operator;;;;; 215 | 341;q;generalized coordinate;;;;; 216 | 341;p;generalized momentum;;;;; 217 | 341;t;duration;;;;; 218 | 341;L;Lagrange function;;;;; 219 | 341;q;generalized velocity;;;;; 220 | 341;Hamiltonian operator;H;;;;; 221 | 341;generalized coordinate;q;;;;; 222 | 341;generalized momentum;p;;;;; 223 | 341;duration;t;;;;; 224 | 341;Lagrange function;L;;;;; 225 | 341;generalized velocity;q;;;;; 226 | 342;\partial;partial derivative symbol;;;;; 227 | 342;S;action;;;;; 228 | 342;t;duration;;;;; 229 | 342;H;Hamiltonian function;;;;; 230 | 342;partial derivative symbol;\partial;;;;; 231 | 342;action;S;;;;; 232 | 342;duration;t;;;;; 233 | 342;Hamiltonian function;H;;;;; 234 | 343;F;force;;;;; 235 | 343;k;spring constant;;;;; 236 | 343;X;linear strain;;;;; 237 | 343;force;F;;;;; 238 | 343;spring constant;k;;;;; 239 | 343;linear strain;X;;;;; 240 | 344;\zeta;jerk;;;;; 241 | 344;\alpha;acceleration;;;;; 242 | 344;t;duration;;;;; 243 | 344;jerk;\zeta;;;;; 244 | 344;acceleration;\alpha;;;;; 245 | 344;duration;t;;;;; 246 | 345;T;kinetic energy;;;;; 247 | 345;m;mass;;;;; 248 | 345;v;speed;;;;; 249 | 345;kinetic energy;T;;;;; 250 | 345;mass;m;;;;; 251 | 345;speed;v;;;;; 252 | 346;L;Lagrangian operator;;;;; 253 | 346;T;kinetic energy;;;;; 254 | 346;V;potential energy;;;;; 255 | 346;Lagrangian operator;L;;;;; 256 | 346;kinetic energy;T;;;;; 257 | 346;potential energy;V;;;;; 258 | 347;\gamma;Lorentz factor;;;;; 259 | 347;v;velocity;;;;; 260 | 347;c;speed of light;;;;; 261 | 347;Lorentz factor;\gamma;;;;; 262 | 347;velocity;v;;;;; 263 | 347;speed of light;c;;;;; 264 | 348;F;Lorentz force;;;;; 265 | 348;q;electric charge;;;;; 266 | 348;E;electric field;;;;; 267 | 348;v;velocity;;;;; 268 | 348;B;magnetic field;;;;; 269 | 348;Lorentz force;F;;;;; 270 | 348;electric charge;q;;;;; 271 | 348;electric field;E;;;;; 272 | 348;velocity;v;;;;; 273 | 348;magnetic field;B;;;;; 274 | 349;t';time;;;;; 275 | 349;\gamma;Lorentz factor;;;;; 276 | 349;v;velocity;;;;; 277 | 349;x;location;;;;; 278 | 349;c;speed of light;;;;; 279 | 349;time;t';;;;; 280 | 349;Lorentz factor;\gamma;;;;; 281 | 349;velocity;v;;;;; 282 | 349;location;x;;;;; 283 | 349;speed of light;c;;;;; 284 | 350;E;energy;;;;; 285 | 350;m;mass;;;;; 286 | 350;c;speed of light;;;;; 287 | 350;energy;E;;;;; 288 | 350;mass;m;;;;; 289 | 350;speed of light;c;;;;; 290 | 351;Z;mechanical impedance;;;;; 291 | 351;Z;acoustic impedance;;;;; 292 | 351;A;area;;;;; 293 | 351;mechanical impedance;Z;;;;; 294 | 351;acoustic impedance;Z;;;;; 295 | 351;area;A;;;;; 296 | 352;J;moment of inertia;;;;; 297 | 352;r;radial distance;;;;; 298 | 352;m;mass;;;;; 299 | 352;moment of inertia;J;;;;; 300 | 352;radial distance;r;;;;; 301 | 352;mass;m;;;;; 302 | 353;p;momentum;;;;; 303 | 353;m;mass;;;;; 304 | 353;v;velocity;;;;; 305 | 353;momentum;p;;;;; 306 | 353;mass;m;;;;; 307 | 353;velocity;v;;;;; 308 | 354;F;force;;;;; 309 | 354;m;mass;;;;; 310 | 354;a;acceleration;;;;; 311 | 354;force;F;;;;; 312 | 354;mass;m;;;;; 313 | 354;acceleration;a;;;;; 314 | 355;F;force;;;;; 315 | 355;force;F;;;;; 316 | 356;z;linear strain;;;;; 317 | 356;A;amplitude;;;;; 318 | 356;\zeta;damping ratio;;;;; 319 | 356;\omega;angular velocity;;;;; 320 | 356;t;duration;;;;; 321 | 356;\varphi;phase;;;;; 322 | 356;linear strain;z;;;;; 323 | 356;amplitude;A;;;;; 324 | 356;damping ratio;\zeta;;;;; 325 | 356;angular velocity;\omega;;;;; 326 | 356;duration;t;;;;; 327 | 356;phase;\varphi;;;;; 328 | 357;\theta;angular displacement;;;;; 329 | 357;t;duration;;;;; 330 | 357;g;gravitational acceleration;;;;; 331 | 357;l;length;;;;; 332 | 357;angular displacement;\theta;;;;; 333 | 357;duration;t;;;;; 334 | 357;gravitational acceleration;g;;;;; 335 | 357;length;l;;;;; 336 | 358;P;power;;;;; 337 | 358;E;energy;;;;; 338 | 358;t;duration;;;;; 339 | 358;power;P;;;;; 340 | 358;energy;E;;;;; 341 | 358;duration;t;;;;; 342 | 359;\omega;radial velocity;;;;; 343 | 359;\phi;angle;;;;; 344 | 359;t;duration;;;;; 345 | 359;v;velocity;;;;; 346 | 359;r;radius;;;;; 347 | 359;radial velocity;\omega;;;;; 348 | 359;angle;\phi;;;;; 349 | 359;duration;t;;;;; 350 | 359;velocity;v;;;;; 351 | 359;radius;r;;;;; 352 | 360;E;rest energy;;;;; 353 | 360;m;rest mass;;;;; 354 | 360;c;speed of light;;;;; 355 | 360;rest energy;E;;;;; 356 | 360;rest mass;m;;;;; 357 | 360;speed of light;c;;;;; 358 | 361;m;mass;;;;; 359 | 361;c;speed of light;;;;; 360 | 361;E;energy;;;;; 361 | 361;p;momentum;;;;; 362 | 361;mass;m;;;;; 363 | 361;speed of light;c;;;;; 364 | 361;energy;E;;;;; 365 | 361;momentum;p;;;;; 366 | 362;R;Rossby number;;;;; 367 | 362;v;speed;;;;; 368 | 362;l;characteristic length;;;;; 369 | 362;E;Earth's angular frequency;;;;; 370 | 362;\sin;sine;;;;; 371 | 362;\varphi;latitude;;;;; 372 | 362;Rossby number;R;;;;; 373 | 362;speed;v;;;;; 374 | 362;characteristic length;l;;;;; 375 | 362;Earth's angular frequency;E;;;;; 376 | 362;sine;\sin;;;;; 377 | 362;latitude;\varphi;;;;; 378 | 363;v;speed;;;;; 379 | 363;s;distance;;;;; 380 | 363;t;duration;;;;; 381 | 363;speed;v;;;;; 382 | 363;distance;s;;;;; 383 | 363;duration;t;;;;; 384 | 364;c;speed of light;;;;; 385 | 364;f;frequency;;;;; 386 | 364;\lambda;wavelength;;;;; 387 | 364;speed of light;c;;;;; 388 | 364;frequency;f;;;;; 389 | 364;wavelength;\lambda;;;;; 390 | 365;x;coordinate;;;;; 391 | 365;y;coordinate;;;;; 392 | 365;z;coordinate;;;;; 393 | 365;r;radius;;;;; 394 | 365;coordinate;x;;;;; 395 | 365;coordinate;y;;;;; 396 | 365;coordinate;z;;;;; 397 | 365;radius;r;;;;; 398 | 366;\psi;linear strain;;;;; 399 | 366;A;amplitude;;;;; 400 | 366;k;wavenumber;;;;; 401 | 366;x;location;;;;; 402 | 366;\omega;angular velocity;;;;; 403 | 366;t;duration;;;;; 404 | 366;\varphi;phase;;;;; 405 | 366;linear strain;\psi;;;;; 406 | 366;amplitude;A;;;;; 407 | 366;wavenumber;k;;;;; 408 | 366;location;x;;;;; 409 | 366;angular velocity;\omega;;;;; 410 | 366;duration;t;;;;; 411 | 366;phase;\varphi;;;;; 412 | 367;F;fictitious force;;;;; 413 | 367;\pi;pi;;;;; 414 | 367;\mu;dynamic viscosity;;;;; 415 | 367;R;radius;;;;; 416 | 367;V;flow velocity;;;;; 417 | 367;fictitious force;F;;;;; 418 | 367;pi;\pi;;;;; 419 | 367;dynamic viscosity;\mu;;;;; 420 | 367;radius;R;;;;; 421 | 367;flow velocity;V;;;;; 422 | 368;\sigma;stress;;;;; 423 | 368;F;force;;;;; 424 | 368;A;area;;;;; 425 | 368;stress;\sigma;;;;; 426 | 368;force;F;;;;; 427 | 368;area;A;;;;; 428 | 369;\alpha;angular acceleration;;;;; 429 | 369;v;velocity;;;;; 430 | 369;t;duration;;;;; 431 | 369;angular acceleration;\alpha;;;;; 432 | 369;velocity;v;;;;; 433 | 369;duration;t;;;;; 434 | 370;v;velocity;;;;; 435 | 370;\omega;angular velocity;;;;; 436 | 370;r;radius;;;;; 437 | 370;velocity;v;;;;; 438 | 370;angular velocity;\omega;;;;; 439 | 370;radius;r;;;;; 440 | 371;T;torque;;;;; 441 | 371;M;moment of force;;;;; 442 | 371;e;unit vector;;;;; 443 | 371;torque;T;;;;; 444 | 371;moment of force;M;;;;; 445 | 371;unit vector;e;;;;; 446 | 372;s;displacement;;;;; 447 | 372;v;velocity;;;;; 448 | 372;t;duration;;;;; 449 | 372;displacement;s;;;;; 450 | 372;velocity;v;;;;; 451 | 372;duration;t;;;;; 452 | 373;v;velocity;;;;; 453 | 373;r;position vector;;;;; 454 | 373;t;duration;;;;; 455 | 373;velocity;v;;;;; 456 | 373;position vector;r;;;;; 457 | 373;duration;t;;;;; 458 | 374;\sigma;wavenumber;;;;; 459 | 374;\lambda;wavelength;;;;; 460 | 374;wavenumber;\sigma;;;;; 461 | 374;wavelength;\lambda;;;;; 462 | 375;A;work;;;;; 463 | 375;F;force;;;;; 464 | 375;r;position vector;;;;; 465 | 375;work;A;;;;; 466 | 375;force;F;;;;; 467 | 375;position vector;r;;;;; 468 | --------------------------------------------------------------------------------