--[[ Complex Number Tagged Data Module H. Conrad Cunningham, Professor Computer and Information Science University of Mississippi The Complex Number set of modules illustrates how we can use data abstraction to design a module that allows multiple representations of the data to be used simultaneously. Developed for CSci 658, Software Language Engineering, Fall 2013 1234567890123456789012345678901234567890123456789012345678901234567890 2013-09-20: Translated SICP Scheme code to Lua draft 2013-09-21: Prototyped complex number modules 2013-09-22: Added require of utilities and data tagging modules See the "complexRectangular" module for more extensive comments on the overall package. This package uses tagged data to enable handling of both rectangular and polar representations of the data. --]] -- Load complex number utilities module local util = require "complexUtilities" -- local definitions for convenience local square = util.square local show_data = util.show_data -- SICP Section 2.4.2: Tagged Data -- Tagging -- Load Data Tagging module local dt = require "dataTagging" -- local definitions for convenience local attach_tag, is_tagged = dt.attach_tag, dt.is_tagged local type_tag, contents = dt.type_tag, dt.contents -- Tags local RECTANGULAR_TAG, POLAR_TAG = "rectangular", "polar" -- Display names local RECTANGULAR, POLAR = "Rectangular", "Polar" local function is_rectangular(z) -- rectangular? return type_tag(z) == RECTANGULAR_TAG end local function is_polar(z) -- polar? return type_tag(z) == POLAR_TAG end -- Revised rectangular representation (Ben) -- Tag same representation used in Rectangular module local function real_part_rectangular(z) return z.real end local function imag_part_rectangular(z) return z.imag end local function magnitude_rectangular(z) return math.sqrt( square(real_part_rectangular(z)) + square(imag_part_rectangular(z)) ) end local function angle_rectangular(z) return math.atan2( imag_part_rectangular(z), real_part_rectangular(z) ) end local function make_from_real_imag_rectangular(x,y) return attach_tag( RECTANGULAR_TAG, { real = x, imag = y } ) end local function make_from_mag_ang_rectangular(r,a) return attach_tag( RECTANGULAR_TAG, { real = r * math.cos(a), imag = r * math.sin(a) } ) end -- Revised polar representation (Alyssa) -- Tag same representation used in Polar module local function magnitude_polar(z) return z.magnitude end local function angle_polar(z) return z.angle end local function real_part_polar(z) return magnitude_polar(z) * math.cos(angle_polar(z)) end local function imag_part_polar(z) return magnitude_polar(z) * math.sin (angle_polar(z)) end local function make_from_real_imag_polar(x,y) return attach_tag( POLAR_TAG, { magnitude = math.sqrt(square(x) + square(y)), angle = math.atan2(y,x) } ) end local function make_from_mag_ang_polar(r,a) return attach_tag( POLAR_TAG, { magnitude = r, angle = a } ) end -- Constructors for complex numbers local function make_from_real_imag(x,y) return make_from_real_imag_rectangular(x,y) end local function make_from_mag_ang(r,a) return make_from_mag_ang_polar(r,a) end -- Generic selectors local function real_part(z) if is_rectangular(z) then return real_part_rectangular(contents(z)) elseif is_polar(z) then return real_part_polar(contents(z)) else error("Unknown type -- REAL_PART" .. show_data(z), 2) end end local function imag_part(z) if is_rectangular(z) then return imag_part_rectangular(contents(z)) elseif is_polar(z) then return imag_part_polar(contents(z)) else error("Unknown type -- IMAG_PART" .. shoe_data(z), 2) end end local function magnitude(z) if is_rectangular(z) then return magnitude_rectangular(contents(z)) elseif is_polar(z) then return magnitude_polar(contents(z)) else error("Unknown type -- MAGNITUDE" .. show_data(z), 2) end end local function angle(z) if is_rectangular(z) then return angle_rectangular(contents(z)) elseif is_polar(z) then return angle_polar(contents(z)) else error("Unknown type -- ANGLE" .. show_data(z), 2) end end -- Added function: Convert representation to string local function to_string(z) if is_rectangular(z) then return RECTANGULAR .. "(" .. tostring(real_part(z)) .. ", " .. tostring(imag_part(z)) .. ")" elseif is_polar(z) then return POLAR .. "(" .. tostring(magnitude(z)) .. ", " .. tostring(angle(z)) .. ")" else error("Unknown type -- to_string" .. show_data(z), 2) end end -- Complex arithmetic (no change from previous section) local function add_complex(z1,z2) return make_from_real_imag( real_part(z1) + real_part(z2), imag_part(z1) + imag_part(z2) ) end local function sub_complex(z1,z2) return make_from_real_imag( real_part(z1) - real_part(z2), imag_part(z1) - imag_part(z2) ) end local function mul_complex(z1,z2) return make_from_mag_ang( magnitude(z1) * magnitude(z2), angle(z1) + angle(z2) ) end local function div_complex(z1,z2) return make_from_mag_ang( magnitude(z1) / magnitude(z2), angle(z1) - angle(z2) ) end -- Module Export return { make_from_real_imag = make_from_real_imag, make_from_mag_ang = make_from_mag_ang, real_part = real_part, imag_part = imag_part, magnitude = magnitude, angle = angle, add_complex = add_complex, sub_complex = sub_complex, mul_complex = mul_complex, div_complex = div_complex, to_string = to_string }