Automated Feedback Generation Tool for Programming Assignments

automated feedback generation for introductory n.w
1 / 52
Embed
Share

Explore the advancements in automated feedback generation for introductory programming assignments, addressing challenges like relating failing inputs to errors and scalability concerns in MOOCs. Discover the impact of test-cases based feedback and autograder workflows, along with the benefits and challenges associated with the process.

  • Feedback Generation
  • Programming Assignments
  • Automated Tools
  • Scalability
  • Test-Cases

Uploaded on | 0 Views


Download Presentation

Please find below an Image/Link to download the presentation.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.

You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.

E N D

Presentation Transcript


  1. Automated Feedback Generation for Introductory Programming Assignments Rishabh Singh, Sumit Gulwani, Armando Solar-Lezama

  2. Test-cases based feedback Hard to relate failing inputs to errors Manual feedback by TAs Time consuming and error prone Feedback on Programming Assignments 2

  3. Scalability Challenges (>100k students) Bigger Challenge in MOOCs 3

  4. Todays Grading Workflow def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return deriv for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return deriv for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv replace derive by [0] Grading Rubric Teacher s Solution 4

  5. Autograder Workflow def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return deriv for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return deriv for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv replace derive by [0] Error Model Teacher s Solution 5

  6. Good News (Assumptions) The complete specification is known. Errors are predictable. 6

  7. Bad News (Challenges) Reasoning about equivalence Models that describe the classes of errors Coordinated fixes in multiple places 7

  8. Running Example 8

  9. computeDeriv Compute the derivative of a polynomial poly = [10, 8, 2] #f(x) = 10 + 8x +2x2 => [8, 4] #f (x) = 8 + 4x 9

  10. Teachers solution def computeDeriv(poly): result = [] if len(poly) == 1: return [0] for i in range(1, len(poly)): result += [i * poly[i]] return result 10

  11. Students submission def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return deriv for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv 11

  12. Students submission def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): returnderiv [0] for e in range(0 1, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv 12

  13. Autograder Algorithm 13

  14. Algorithm .eml Rewriter Translator . ?? Solver Feedback .out ---- ---- .py .sk 14

  15. Algorithm: Rewriter .eml Rewriter Translator Solver Feedback .py . ?? 15

  16. Simplified Error Model return a return [0] range(a1, a2) range(a1+1,a2) a0 == a1 False 16

  17. Rewriting using Error Model range(0, len(poly)) range({0 ,1}, len(poly)) default choice a a+1 17

  18. Rewriting using Error Model range(0, len(poly)) range({0 ,1}, len(poly)) a a+1 18

  19. Rewriting using Error Model range(0, len(poly)) range({0 ,1}, len({poly, poly+1})) a a+1 19

  20. Rewriting using Error Model range(0, len(poly)) range({0 ,1}, {len({poly, poly+1}), len({poly, poly+1})+1}) a a+1 20

  21. Rewriting using Error Model ( ??) def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return a range(a1, a2) range(a1+1,a2) a0 == a1 False return [0] return {deriv,[0]} for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return {deriv,[0]} 21

  22. Rewriting using Error Model ( ??) def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return a return [0] range(a1, a2) a0 == a1 False range(a1+1,a2) return {deriv,[0]} for e inrange({0,1}, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return {deriv,[0]} 22

  23. Rewriting using Error Model ( ??) def computeDeriv(poly): deriv = [] zero = 0 if({len(poly) == 1, False}): return a return [0] range(a1, a2) range(a1+1,a2) a0 == a1 False return {deriv,[0]} for e in range({0,1}, len(poly)): if({poly[e] == 0, False}): zero += 1 else: deriv.append(poly[e]*e) return {deriv,[0]} 23

  24. Rewriting using Error Model ( ??) def computeDeriv(poly): deriv = [] zero = 0 if ({len(poly) == 1, False}): Problem: Find a program that minimizes cost metric and is functionally equivalent with teacher s solution return {deriv,[0]} for e in range({0,1}, len(poly)): if ({poly[e] == 0, False}): zero += 1 else: deriv.append(poly[e]*e) return {deriv,[0]} 24

  25. Algorithm: Translator Rewriter Translator . ?? Solver Feedback .sk 25

  26. Sketch [Solar-Lezama et al. ASPLOS06] void main(int x){ int k = ??; assert x + x == k * x; } void main(int x){ int k = 2; assert x + x == k * x; } Statically typed C-like language with holes 26

  27. ??Translation to Sketch (1) Handling python s dynamic types (2) Translation of expression choices 27

  28. (1) Handling Dynamic Types struct MultiType{ int type; int ival; bit bval; MTString str; MTList lst; MTDict dict; MTTuple tup; } ival bval bool int Type lst list 28

  29. Python Constants using MultiType - bool 2 - bool 1 1 2 int int INT INT - - - - list list - - [1,2] bool int LIST - len=2, lVals = { *, * } list 29

  30. Python Exprs using MultiType x + y 5 10 int 15 int - - - int bool bool bool INT INT INT - - - - - - list list list 30

  31. Python Exprs using MultiType x + y - - - - - - int bool int int bool bool LIST LIST LIST [1,2,3] list [1,2] list [3] list - - - 31

  32. Python Expressions using MultiType x + y Typing rules are encoded as constraints 5 - - - int bool int bool LIST INT [3] list - - - list 32

  33. Python Exprs using MultiType 33

  34. (2) Translation of Expression Choices { , } MultiType modifyMTi( , ){ if(??) return else choicei = True return } - - - - - - - - - - - - - - - - - // default choice - - - // non-default choice - - - - 34

  35. Translation to Sketch (Final Step) harness main(int N, int[N] poly){ MultiType polyMT = MTFromList(poly); MultiType result1 = computeDeriv_teacher(polyMT); MultiType result2 = computeDeriv_student(polyMT); assert MTEquals(result1,result2); } 35

  36. Translation to Sketch (Final Step) harness main(int N, int[N] poly){ totalCost = 0; MultiType polyMT = MTFromList(poly); if(choicek) totalCost++; assert MTEquals(result1,result2); minimize(totalCost); } MultiType result1 = computeDeriv_teacher(polyMT); MultiType result2 = computeDeriv_student(polyMT); Minimum Changes 36

  37. Algorithm: Solver Rewriter Translator Solver Feedback .out .sk 37

  38. Solving for minimize(x) Sketch Uses CEGIS multiple SAT calls MAX-SAT too much overhead Incremental linear search reuse learnt clauses 38

  39. Incremental Solving for minimize(x) (P,x) (P1,x=7) Sketch {x<7} Sketch {x<4} UNSAT (P2,x=4) Sketch 39

  40. Algorithm: Feedback Rewriter Translator Solver Feedback .out ---- ---- 40

  41. Feedback Generation Correction rules associated with Feedback Template Extract synthesizer choices to fill templates 41

  42. Feedback Generation def computeDeriv(poly): deriv = [] zero = 0 if (len(poly) == 1): return deriv for e in range(0, len(poly)): if (poly[e] == 0): zero += 1 else: deriv.append(poly[e]*e) return deriv The program requires 3 changes: In the return statement return deriv in line 5, replace deriv by [0]. In the comparison expression (poly[e] == 0) in line 7, change (poly[e] == 0) to False. In the expression range(0, len(poly)) in line 6, increment 0 by 1. 42

  43. Evaluation 43

  44. Benchmarks Exercises from the Introduction to Programming course at MIT int: prodBySum, compBal, iterPower, recurPower, iterGCD tuple: oddTuple list: compDeriv, evalPoly string: hangman1, hangman2 45

  45. Benchmark evalPoly-6.00 compBal-stdin-6.00 compDeriv-6.00 hangman2-6.00x prodBySum-6.00 oddTuples-6.00 hangman1-6.00x evalPoly-6.00x compDeriv-6.00x oddTuples-6.00x iterPower-6.00x recurPower-6.00x iterGCD-6.00x Test Set 13 52 103 218 268 344 351 541 918 1756 2875 2938 2988 46

  46. 35 30 25 Time (in s) 20 15 10 5 0 Average Running Time (in s) 47

  47. 90.00% 80.00% Feedback Percentage 70.00% 60.00% 50.00% 40.00% 30.00% 20.00% 10.00% 0.00% Feedback Generated (Percentage) 48

  48. Generated Feedback 8579 TestSet 13365 Percentage 64.19% AvgTime(s) 9.91 Average Performance 49

  49. Why low % in some cases? Completely Incorrect Solutions Empty or performing trivial computations Unimplemented Python Language Features Lambda function Timeout Set as 4 mins Big Conceptual Errors Can not be corrected with application of a set of local correction rules 50

  50. Capabilities Subset of Python features Provide feedback Grade more reasonably 53

Related


More Related Content