Initial Commit
This commit is contained in:
		
							
								
								
									
										299
									
								
								intergral.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								intergral.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| # Assignment Name: Integral Approximator | ||||
| # Author: Rekai Nyangadzayi Musuka | ||||
| # Description: Approximates Any Given Function | ||||
| # Inputs: None | ||||
| # Outputs: A Graph in Turtle with the Approximated and Theorized Area, highlighted by drawing trapezoids or squares. | ||||
| # Version: 2019.0107.0 | ||||
|  | ||||
| #LINK TO GRAPH (DESMOS): https://www.desmos.com/calculator/igcdhrepy3 | ||||
|  | ||||
| import math | ||||
| import turtle | ||||
|  | ||||
| CURSOR_SIZE = 0.1 # Makes the "Turtle" Invisible | ||||
| DRAW_SPEED  = 0 | ||||
|  | ||||
| #Cosmetic | ||||
| FONT_FAMILY =  "Consolas" | ||||
| NUM_FONT_SIZE = "8" | ||||
| LABEL_FONT_SIZE = "10" | ||||
| TEXT_SPACING = 15 | ||||
| FIGURES = 5 | ||||
|  | ||||
| # Changes these to mess with the scale of the graph | ||||
| SCALE_X     = 80 # Scale of the X Axis OG: 80 | ||||
| SCALE_Y     = 80 # Scale of the Y Axis OG: 80 | ||||
| UNIT_LENGTH = 400 # Determines the maximum domain and Range of the cartesian plane (in this case (-400, 400) in both X and Y) | ||||
|  | ||||
|  | ||||
| # Best not to mess with these :) | ||||
| MIN_VALUE   = -2 # The Domain of X is -2 <= x <= 2 | ||||
| MAX_VALUE   = 2 | ||||
| TICK_STEP   = 1 # Draw Ticks according to an interval of this variable | ||||
| PLANE_INCREMENT = 1 | ||||
|  | ||||
| # Change DRAW_STEP for a more or less accurately drawn function | ||||
| DRAW_STEP   = 0.01 # What we Increment by when drawing the function | ||||
|  | ||||
| # Change to shorten or lengthen the height of the tick | ||||
| TICK_HEIGHT = 10 # The Height of the Tick line | ||||
|  | ||||
| # Changes How Detailed the Area Approximation (Trapezoid or Rectangle) is (higher is better) | ||||
| ITERATIONS = 100 | ||||
|  | ||||
| # Determines whether the program uses the rectangle rule  | ||||
| # or trapezoid rule (trapezoid is more exact I think?) | ||||
|  | ||||
| # TODO? Implement Simpson's Rule? | ||||
| APPROX_TYPE = "trapezoid" # or square | ||||
|  | ||||
| # Initializing Turtle Variables | ||||
| cursor = turtle.Turtle() | ||||
| win = turtle.Screen() | ||||
| cursor.shape() | ||||
| cursor.hideturtle() | ||||
| cursor.speed(DRAW_SPEED) | ||||
|  | ||||
| # Draws a Cursor Tick | ||||
| def draw_tick(num, cursor, height, x_axis = False): | ||||
|    | ||||
|   # Function draws the numerical value of the x or y value at any given tick | ||||
|   def draw_num(angle, distance, num): | ||||
|     cursor.penup() | ||||
|     cursor.left(angle) | ||||
|     cursor.forward(distance) | ||||
|     cursor.write(num, align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
|     cursor.backward(distance) | ||||
|     cursor.left(-angle) | ||||
|     cursor.pendown() | ||||
|  | ||||
|   if x_axis: | ||||
|     draw_num(-90, (TICK_HEIGHT * 2), num) | ||||
|   else: | ||||
|     draw_num(90, (TICK_HEIGHT * 2), num) | ||||
|  | ||||
|   for angle in [90, -180]:  | ||||
|     cursor.left(angle) | ||||
|     cursor.forward(height / 2) | ||||
|     cursor.backward(height / 2) | ||||
|   cursor.left(90) | ||||
|    | ||||
|  | ||||
| # Draws the Cartesian Plane | ||||
| def create_plane(): | ||||
|   cursor.penup() | ||||
|  | ||||
|   cursor.goto(-UNIT_LENGTH, 0) # Goes to Fartheset left coordinate | ||||
|   cursor.pendown() | ||||
|  | ||||
|   # Function will draw text nearby a given x value (used to draw axis labels). | ||||
|   def draw_axis_label(angle, distance, text): | ||||
|     cursor.penup() | ||||
|     cursor.left(angle) | ||||
|     cursor.forward(distance) | ||||
|     cursor.write(text, align="center", font=(FONT_FAMILY, LABEL_FONT_SIZE, "normal")) | ||||
|     cursor.backward(distance) | ||||
|     cursor.left(-angle) | ||||
|     cursor.pendown() | ||||
|  | ||||
|   # This draws the x line of the cartesian plane | ||||
|   while (cursor.pos()[0]  <= UNIT_LENGTH):  | ||||
|     if (cursor.pos()[0] == -UNIT_LENGTH): draw_axis_label(-90, TICK_HEIGHT * 4, "X Axis") # If x is the furthermost left value, draw the x axis label below | ||||
|     if (cursor.pos()[0] % (TICK_STEP * SCALE_X) == 0): draw_tick(cursor.pos()[0], cursor, TICK_HEIGHT, True) # Draw ticks whenever the condition is met | ||||
|     cursor.forward(PLANE_INCREMENT) | ||||
|    | ||||
|   cursor.penup() | ||||
|   cursor.goto(0, -UNIT_LENGTH) # Goes to the farthest bottom coordinate | ||||
|   cursor.pendown() | ||||
|   cursor.left(90) | ||||
|    | ||||
|   # This draws the y line of the cartesian plane | ||||
|   while (cursor.pos()[1]  <= UNIT_LENGTH): | ||||
|     if (cursor.pos()[1] == -UNIT_LENGTH): draw_axis_label(90, TICK_HEIGHT * 4, "Y Axis") # If y is the furthermost bottom value, draw the y axis label there | ||||
|     if (cursor.pos()[1] % (TICK_STEP * SCALE_Y) == 0): draw_tick(cursor.pos()[1], cursor, TICK_HEIGHT, True) # Draw ticks whenever the if condition is met | ||||
|     cursor.forward(PLANE_INCREMENT) | ||||
|    | ||||
|   cursor.penup() | ||||
|  | ||||
| # Used for Calculus Portion of Program | ||||
| def draw_rectangle(length, width): | ||||
|   arr = [width, length, width, length] | ||||
|   i = 0 | ||||
|  | ||||
|   while (i < len(arr)): | ||||
|     cursor.forward(arr[i]) | ||||
|     cursor.left(90) | ||||
|     i += 1 | ||||
|    | ||||
|   cursor.penup() | ||||
|   cursor.forward(width) | ||||
|   cursor.pendown() | ||||
|  | ||||
|  | ||||
| # Used for Calculus Portion of Program | ||||
| # Should Rewrite this sometime | ||||
| def draw_trapezoid(a, b, h): | ||||
|   # Drawing Trapezoid given Area | ||||
|   width_of_triangle = b - a  | ||||
|  | ||||
|   c = math.sqrt(math.pow(h, 2) + math.pow(width_of_triangle, 2)) | ||||
|  | ||||
|   angle = math.atan2(h, width_of_triangle) * (180 / math.pi) | ||||
|  | ||||
|   cursor.forward(h) | ||||
|   cursor.left(90) | ||||
|   cursor.forward(b) | ||||
|  | ||||
|   cursor.left(180 - angle) | ||||
|   cursor.forward(c) | ||||
|   cursor.left(angle) | ||||
|   cursor.forward(a) | ||||
|   cursor.left(90) | ||||
|  | ||||
|   cursor.penup() | ||||
|   cursor.forward(h) | ||||
|   cursor.pendown() | ||||
|  | ||||
|  | ||||
| # The function that draws the upper half of the Heart | ||||
| def f(x): | ||||
|   return math.sqrt(1 - ((math.fabs(x) - 1) ** 2)) | ||||
|  | ||||
| # The function that draws the Lower Half the the Heart | ||||
| def g(x): | ||||
|   return -3 * math.sqrt(1 - math.sqrt(math.fabs(x) / 2 )) | ||||
|  | ||||
| # Calls create_plane() which draws and labels the cartesian plane. | ||||
| create_plane() | ||||
|  | ||||
|  | ||||
| # This will set x to -2 and this while loop will then draw f(x) at -2 to 2 | ||||
| # Iterates between MIN_VALUE and MAX_VALUE and draws the calculated y value given the x value | ||||
| x = MIN_VALUE | ||||
| while (x <= MAX_VALUE): | ||||
|   cursor.goto(SCALE_X * x, SCALE_Y * f(x)) # f(x) is the top half of the heart | ||||
|   cursor.pendown() | ||||
|   x += DRAW_STEP | ||||
|  | ||||
| cursor.penup() | ||||
|  | ||||
| # # This will set x to -2 and loop through g(x) until it reaches 2 | ||||
| # # Iterates between MIN_VALUE and MAX_VALUE and draws the calculated y value given the x value | ||||
| x = MIN_VALUE | ||||
| while (x <= MAX_VALUE): | ||||
|   cursor.goto(SCALE_X * x, SCALE_Y * g(x)) # g(x) is the bottom half of the heart | ||||
|   cursor.pendown() | ||||
|   x += DRAW_STEP | ||||
|  | ||||
|  | ||||
| # This code draws the functions used onto the screen. | ||||
| cursor.penup() | ||||
| cursor.goto(UNIT_LENGTH / 2, UNIT_LENGTH / 2) # We go to the middle of quadrant I | ||||
| cursor.right(180) | ||||
| cursor.write("Functions:", align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.write("Top: y = math.sqrt(1 - ((math.abs(x) - 1) ** 2))", align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.write("Bottom: y= math.sqrt(1 - math.sqrt(math.abs(x) / 2 ))", align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
|  | ||||
| # Intergral Stuff Goes Here  | ||||
|  | ||||
| cursor.left(90) # Settings Cursor Back to it's default position (heading right) | ||||
|  | ||||
|  | ||||
| # Allows us to import a reasonably acccurate estimate as to what the intergral of a given function will be | ||||
| # By accurate I mean more accurate than our estimate. | ||||
| import scipy.integrate as integrate | ||||
|  | ||||
| # Calculates Percent Error (the one we learned in chemistry) | ||||
| def percent_error(exper, accept): | ||||
|   return (math.fabs(exper - accept) / accept) * 100 | ||||
|  | ||||
| # Approximates the intergral of a function using the square rule. | ||||
| def approx_integral_square(func, a, b, n): | ||||
|   # n is how many rectangles you want. | ||||
|   # area is length * width | ||||
|   area = 0.0 | ||||
|   width = (b - a) / n | ||||
|   i = 1 | ||||
|  | ||||
|   while (i <= n): | ||||
|     height = func(a + (i - 1) * width) | ||||
|  | ||||
|     draw_rectangle(height * SCALE_Y, width * SCALE_Y) | ||||
|  | ||||
|     area += width * height | ||||
|     i += 1 | ||||
|  | ||||
|   return area | ||||
|  | ||||
| # Approximates the integral of a function using the trapezoid rule. | ||||
| def approx_integral_trapezoid(func, a, b, n):  | ||||
|   # n is how many trapezoids you want | ||||
|   width = (b - a) / n  | ||||
|   res = func(a) + func(b) | ||||
|   i = 1 | ||||
|    | ||||
|   prev_height = func(a) | ||||
|  | ||||
|   while (i < n): | ||||
|     height = func(a + (i * width)) | ||||
|     draw_trapezoid(prev_height * SCALE_Y, height * SCALE_Y, width * SCALE_Y) | ||||
|     res += 2 * height  | ||||
|  | ||||
|     prev_height = height | ||||
|     i += 1 | ||||
|  | ||||
|   return (width / 2) * res | ||||
|  | ||||
|  | ||||
| # Exact Results | ||||
| upper_area = integrate.quad(lambda x: f(x), MIN_VALUE, MAX_VALUE) | ||||
| lower_area = integrate.quad(lambda x: g(x), MIN_VALUE, MAX_VALUE) | ||||
|  | ||||
| # Don't really care for the margin of error at the moment | ||||
| # Absolute Value of the area because we don't care about signed area at the moment.math. | ||||
| upper_area = math.fabs(upper_area[0]) | ||||
| lower_area = math.fabs(lower_area[0]) | ||||
|  | ||||
| upper_area_approx = 0 | ||||
| lower_area_approx = 0 | ||||
|  | ||||
| if (APPROX_TYPE == "square"): | ||||
|   cursor.goto(MIN_VALUE * SCALE_X, 0) | ||||
|   upper_area_approx = math.fabs(approx_integral_square(lambda x: f(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
|    | ||||
|   cursor.goto(MIN_VALUE * SCALE_X, 0) | ||||
|   lower_area_approx = math.fabs(approx_integral_square(lambda x: g(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
| elif (APPROX_TYPE == "trapezoid"): | ||||
|   cursor.goto(MIN_VALUE * SCALE_X, 0) | ||||
|   upper_area_approx = math.fabs(approx_integral_trapezoid(lambda x: f(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
|    | ||||
|   cursor.goto(MIN_VALUE * SCALE_X, 0) | ||||
|   lower_area_approx = math.fabs(approx_integral_trapezoid(lambda x: g(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
|  | ||||
|  | ||||
| # Probably Want to Display the Results or smth here. | ||||
|  | ||||
| cursor.penup() | ||||
| cursor.goto(-(UNIT_LENGTH / 2), UNIT_LENGTH / 2) # We go to the middle of quadrant II | ||||
| cursor.right(90) | ||||
| if (APPROX_TYPE == "square"): | ||||
|   cursor.write("Using the Square Rule:", align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
| else: | ||||
|   cursor.write("Using the Trapezoid Rule:", align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
|  | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.forward(TEXT_SPACING) | ||||
|  | ||||
| cursor.write(("Approximated Top Half Area: " + str(round(upper_area_approx, FIGURES)) + " | Theorized: " + str(round(upper_area, FIGURES))), align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.write(("Percent Error: " + str(round(percent_error(upper_area_approx, upper_area), FIGURES)) + "%"), align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
|  | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.write(("Approximated Bottom Half Area: " + str(round(lower_area_approx, FIGURES)) + " | Theorized: " + str(round(lower_area, FIGURES))), align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
| cursor.forward(TEXT_SPACING) | ||||
| cursor.write(("Percent Error: " + str(round(percent_error(lower_area_approx, lower_area), FIGURES)) + "%"), align="center", font=(FONT_FAMILY, NUM_FONT_SIZE, "normal")) | ||||
|  | ||||
| win.exitonclick() | ||||
							
								
								
									
										147
									
								
								testing.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								testing.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| import math | ||||
| import turtle | ||||
| import scipy.integrate as integrate | ||||
|  | ||||
| MIN_VALUE = -2 | ||||
| MAX_VALUE = 2 | ||||
| ITERATIONS = 100 | ||||
|  | ||||
| TURTLE_SCALE = 100 | ||||
|  | ||||
| #### TURTLE STUFF | ||||
| cursor = turtle.Turtle() | ||||
| win = turtle.Screen() | ||||
| cursor.shape() | ||||
| cursor.hideturtle() | ||||
| cursor.speed(0) | ||||
| cursor.goto(-2, 0) | ||||
|  | ||||
| def draw_rectangle(length, width): | ||||
|   arr = [width, length, width, length] | ||||
|   i = 0 | ||||
|  | ||||
|   while (i < len(arr)): | ||||
|     cursor.forward(arr[i]) | ||||
|     cursor.left(90) | ||||
|     i += 1 | ||||
|    | ||||
|   cursor.penup() | ||||
|   cursor.forward(width) | ||||
|   cursor.pendown() | ||||
|  | ||||
| def draw_trapezoid(a, b, h): | ||||
|   # Drawing Trapezoid given Area | ||||
|   width_of_triangle = b - a  | ||||
|  | ||||
|   c = math.sqrt(math.pow(h, 2) + math.pow(width_of_triangle, 2)) | ||||
|  | ||||
|   angle = math.atan2(h, width_of_triangle) * (180 / math.pi) | ||||
|  | ||||
|   cursor.forward(h) | ||||
|   cursor.left(90) | ||||
|   cursor.forward(b) | ||||
|  | ||||
|   cursor.left(180 - angle) | ||||
|   cursor.forward(c) | ||||
|   cursor.left(angle) | ||||
|   cursor.forward(a) | ||||
|   cursor.left(90) | ||||
|  | ||||
|   cursor.penup() | ||||
|   cursor.forward(h) | ||||
|   cursor.pendown() | ||||
| ### | ||||
|  | ||||
| # The function that draws the upper half of the Heart | ||||
| def f(x): | ||||
|   return math.sqrt(1 - ((math.fabs(x) - 1) ** 2)) | ||||
|  | ||||
| # The function that draws the Lower Half the the Heart | ||||
| def g(x): | ||||
|   return -3 * math.sqrt(1 - math.sqrt(math.fabs(x) / 2 )) | ||||
|  | ||||
| def percent_error(exper, accept): | ||||
|   return (math.fabs(exper - accept) / accept) * 100 | ||||
|  | ||||
| def approx_integral_square(func, a, b, n): | ||||
|   # n is how many rectangles you want. | ||||
|   # area is length * width | ||||
|   area = 0.0 | ||||
|   width = (b - a) / n | ||||
|   i = 1 | ||||
|  | ||||
|   while (i <= n): | ||||
|     height = func(a + (i - 1) * width) | ||||
|  | ||||
|     # draw_rectangle(height * TURTLE_SCALE, width * TURTLE_SCALE) | ||||
|  | ||||
|     area += width * height | ||||
|     i += 1 | ||||
|  | ||||
|   return area | ||||
|  | ||||
| def approx_integral_trapezoid(func, a, b, n):  | ||||
|   # n is how many trapezoids you want | ||||
|   width = (b - a) / n  | ||||
|   res = func(a) + func(b) | ||||
|   i = 1 | ||||
|    | ||||
|   prev_height = func(a) | ||||
|  | ||||
|   while (i < n): | ||||
|     height = func(a + (i * width)) | ||||
|     draw_trapezoid(prev_height * TURTLE_SCALE, height * TURTLE_SCALE, width * TURTLE_SCALE) | ||||
|     res += 2 * height | ||||
|  | ||||
|     prev_height = height | ||||
|     i += 1 | ||||
|  | ||||
|   return (width / 2) * res | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| # Compare Results | ||||
| upper_area = integrate.quad(lambda x: f(x), MIN_VALUE, MAX_VALUE) | ||||
| lower_area = integrate.quad(lambda x: g(x), MIN_VALUE, MAX_VALUE) | ||||
|  | ||||
| # Don't really care for the margin of error at the moment | ||||
| # Absolute Value of the area because we don't care about signed area at the moment.math. | ||||
| upper_area = math.fabs(upper_area[0]) | ||||
| lower_area = math.fabs(lower_area[0]) | ||||
|  | ||||
|  | ||||
| print("Using the Square Method:") | ||||
|  | ||||
| upper_area_approx = math.fabs(approx_integral_square(lambda x: f(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
| # cursor.goto(-2, 0) | ||||
| lower_area_approx = math.fabs(approx_integral_square(lambda x: g(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
|  | ||||
| print("\nApproximated Top Half Area:", upper_area_approx, "Original:", upper_area) | ||||
| print("Percent Error: ", percent_error(upper_area_approx, upper_area), "%", sep="") | ||||
|  | ||||
| print("\nApproximated Bottom Half Area:", lower_area_approx, "Original:", lower_area) | ||||
| print("Percent Error: ", percent_error(lower_area_approx, lower_area), "%\n", sep="") | ||||
|  | ||||
| print("------") | ||||
| print("\nUsing the Trapezoid Method:") | ||||
|  | ||||
| upper_area_approx = math.fabs(approx_integral_trapezoid(lambda x: f(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
| cursor.goto(-2, 0) | ||||
| lower_area_approx = math.fabs(approx_integral_trapezoid(lambda x: g(x), MIN_VALUE, MAX_VALUE, ITERATIONS)) | ||||
|  | ||||
|  | ||||
| print("\nApproximated Top Half Area:", upper_area_approx, "Original:", upper_area) | ||||
| print("Percent Error: ", percent_error(upper_area_approx, upper_area), "%", sep="") | ||||
|  | ||||
| print("\nApproximated Bottom Half Area:", lower_area_approx, "Original:", lower_area) | ||||
| print("Percent Error: ", percent_error(lower_area_approx, lower_area), "%", sep="") | ||||
|  | ||||
|  | ||||
| # Contratulations! | ||||
|  | ||||
|  | ||||
|  | ||||
| # Figuring out How to draw a Trapezoid in Turtle. | ||||
|  | ||||
| win.exitonclick() | ||||
		Reference in New Issue
	
	Block a user