diff --git a/dsad-2/AS2_PS5_MS_21.py b/dsad-2/AS2_PS5_MS_21.py new file mode 100644 index 0000000..0d95778 --- /dev/null +++ b/dsad-2/AS2_PS5_MS_21.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +import re + + +def _max_subarray_lr(lst, low, mid, high): + """ find the subarray with maximum sum. + + :param lst: list of items containing profits. + :param low: current low index + :param mid: current high index + :param high: current mid index + :return: sum of left+right, left and right subarray index. + """ + + # sum of left subarray. + left_total = 0 + max_left = max_right = 0 + current_total = 0 + for i in range(mid, low-1, -1): + current_total += lst[i].get('profit') + if current_total > left_total: + left_total = current_total + max_left = i + + # sum of right subarray. + right_total = 0 + current_total = 0 + for i in range(mid+1, high+1, 1): + current_total += lst[i].get('profit') + if current_total > right_total: + right_total = current_total + max_right = i + + return left_total + right_total, max_left, max_right + + +def maxProfit_divide_conquer(lst, low, high): + """ Find the maximum profit in a profits array using divide and conquer method. + + :param lst: list of items containing profits. + :param low: current low index + :param high: current high index + :return: maximum profit, profit start index, profit end index + """ + + if low == high: + return lst[low].get('profit'), low, high + else: + mid = (low + high) // 2 + + # recursively divide profits array into left/right halves, and return + # max(left, right, left_right) profit value. + left_total, left_low, left_high = maxProfit_divide_conquer(lst, low, mid) + right_total, right_low, right_high = maxProfit_divide_conquer(lst, mid+1, high) + lr_total, lr_low, lr_high = _max_subarray_lr(lst, low, mid, high) + + # return max(left_total, right_total, left_right_total) along with + # it's respective start/end position in the profits array. + if left_total >= right_total and left_total >= lr_total: + return left_total, left_low, left_high + elif right_total >= left_total and right_total >= lr_total: + return right_total, right_low, right_high + else: + return lr_total, lr_low, lr_high + + +def maxProfit_iterative(lst): + """ find maximum profit along with buy/sell day in a stock price list, + using iterative method. + + :param lst: list of items containing day/stock-price values. + :return: maximum profit, buy day, sell day + """ + profit = 0 + buy_day = min_day = 0 + sell_day = 1 + + for i in range(1, len(lst)): + if lst[i].get('price') - lst[min_day].get('price') > profit: + profit = lst[i].get('price') - lst[min_day].get('price') + sell_day = i + buy_day = min_day + if lst[i].get('price') <= lst[min_day].get('price'): + min_day = i + + return profit, buy_day, sell_day + + +def main(): + """ read input file, compute max-profit using iterative and divide/conquer methods + and write the profit, buy-day, sell-day to output file. + + :return: + """ + + infile = 'inputPS5.txt' + lst = list() + + # read input file and create a list like the following: + # ( + # { 'day': 0, 'price': 10, 'profit': 0 }, + # { 'day': 1, 'price': 20, 'profit': 10 }, + # { 'day': 2, 'price': 15, 'profit': -5}, + # { 'day': 3, 'price': 30, 'profit': 15}, + # ... + # ) + with open(infile, "r") as f: + for line in f: + # process only lines containing the pattern: + # [optional spaces]/[optional spaces] + if re.match('^[0-9]+ */ *[0-9]+$', line): + # split by '/' with 0 or more spaces on either sides. + (day, price) = re.split(r' */ *', line.rstrip()) + day = int(day) + price = int(price) + lst.append({'day': day, 'price': price, 'profit': 0}) + + for i in range(1, len(lst)): + lst[i]['profit'] = lst[i].get('price') - lst[i-1].get('price') + + outfile = 'outputPS5.txt' + with open(outfile, 'w+') as f: + + # some checks. + if len(lst) < 2: + f.write("ERROR: Too few entries.\n") + return + + # find maximum subarray for divide and conquer approach. + # buy_day will be 1 day before the first profit day. + (profit_by_dc, profit_start_day, profit_end_day) = maxProfit_divide_conquer(lst, 0, len(lst)-1) + + # find maximum profit with iterative approach. + (profit_by_iter, buy_day, sell_day) = maxProfit_iterative(lst) + + assert(profit_by_dc == profit_by_iter) + + if profit_by_dc <= 0: + f.write("NOTICE: No profit can be earned by buying and selling a stock.\n") + else: + f.write("""Maximum Profit(Divide & Conquer): {} +Day to buy: {} +Day to sell: {} +""".format(profit_by_dc, lst[profit_start_day-1].get('day'), lst[profit_end_day].get('day'))) + + f.write("""Maximum Profit(Iterative Solution): {} +Day to buy: {} +Day to sell: {} +""".format(profit_by_iter, lst[buy_day].get('day'), lst[sell_day].get('day'))) + + +main() diff --git a/dsad-2/ASSIGNMENT2_PUN_G21.zip b/dsad-2/ASSIGNMENT2_PUN_G21.zip new file mode 100644 index 0000000..b92d04f Binary files /dev/null and b/dsad-2/ASSIGNMENT2_PUN_G21.zip differ diff --git a/dsad-2/designPS5_21.docx b/dsad-2/designPS5_21.docx new file mode 100644 index 0000000..9d5fa20 Binary files /dev/null and b/dsad-2/designPS5_21.docx differ diff --git a/dsad-2/inputPS5.txt b/dsad-2/inputPS5.txt new file mode 100644 index 0000000..885ae86 --- /dev/null +++ b/dsad-2/inputPS5.txt @@ -0,0 +1,17 @@ +0 / 100 +1 / 113 +2 / 110 +3 / 85 +4 / 105 +5 / 102 +6 / 86 +7 / 63 +8 / 81 +9 / 101 +10 / 94 +11 / 106 +12 / 101 +13 / 79 +14 / 94 +15 / 90 +16 / 97 diff --git a/dsad-2/inputPS5__ascending_price.txt b/dsad-2/inputPS5__ascending_price.txt new file mode 100644 index 0000000..8c7cc72 --- /dev/null +++ b/dsad-2/inputPS5__ascending_price.txt @@ -0,0 +1,11 @@ +0 / 100 +1 / 101 +2 / 102 +3 / 103 +4 / 104 +5 / 105 +6 / 106 +7 / 107 +8 / 108 +9 / 109 +10 / 110 \ No newline at end of file diff --git a/dsad-2/inputPS5__days_starting_from_one.txt b/dsad-2/inputPS5__days_starting_from_one.txt new file mode 100644 index 0000000..34c9adf --- /dev/null +++ b/dsad-2/inputPS5__days_starting_from_one.txt @@ -0,0 +1,7 @@ +1 / 1 +2 / 10 +3 / 100 +4 / 1000 +5 / 100 +6 / 10 +7 / 1 \ No newline at end of file diff --git a/dsad-2/inputPS5__descending_price.txt b/dsad-2/inputPS5__descending_price.txt new file mode 100644 index 0000000..c960634 --- /dev/null +++ b/dsad-2/inputPS5__descending_price.txt @@ -0,0 +1,11 @@ +0 / 100 +1 / 99 +2 / 98 +3 / 97 +4 / 96 +5 / 95 +6 / 94 +7 / 93 +8 / 92 +9 / 91 +10 / 90 \ No newline at end of file diff --git a/dsad-2/inputPS5__missing_day_number.txt b/dsad-2/inputPS5__missing_day_number.txt new file mode 100644 index 0000000..7077bd2 --- /dev/null +++ b/dsad-2/inputPS5__missing_day_number.txt @@ -0,0 +1,5 @@ +1 / 1 +2 / 10 +5 / 100 +6 / 10 +7 / 1 \ No newline at end of file diff --git a/dsad-2/inputPS5__multiple_possibilities.txt b/dsad-2/inputPS5__multiple_possibilities.txt new file mode 100644 index 0000000..f9595af --- /dev/null +++ b/dsad-2/inputPS5__multiple_possibilities.txt @@ -0,0 +1,9 @@ +0 / 100 +1 / 100 +2 / 100 +3 / 101 +4 / 100 +5 / 100 +6 / 101 +7 / 101 +8 / 101 \ No newline at end of file diff --git a/dsad-2/inputPS5__no_change_in_price.txt b/dsad-2/inputPS5__no_change_in_price.txt new file mode 100644 index 0000000..d25e118 --- /dev/null +++ b/dsad-2/inputPS5__no_change_in_price.txt @@ -0,0 +1,4 @@ +0 / 100 +1 / 100 +2 / 100 +3 / 100 \ No newline at end of file diff --git a/dsad-2/inputPS5__sample.txt b/dsad-2/inputPS5__sample.txt new file mode 100644 index 0000000..885ae86 --- /dev/null +++ b/dsad-2/inputPS5__sample.txt @@ -0,0 +1,17 @@ +0 / 100 +1 / 113 +2 / 110 +3 / 85 +4 / 105 +5 / 102 +6 / 86 +7 / 63 +8 / 81 +9 / 101 +10 / 94 +11 / 106 +12 / 101 +13 / 79 +14 / 94 +15 / 90 +16 / 97 diff --git a/dsad-2/inputPS5__too_few_entries.txt b/dsad-2/inputPS5__too_few_entries.txt new file mode 100644 index 0000000..9c5f10f --- /dev/null +++ b/dsad-2/inputPS5__too_few_entries.txt @@ -0,0 +1 @@ +0 / 100 \ No newline at end of file diff --git a/dsad-2/outputPS5.txt b/dsad-2/outputPS5.txt new file mode 100644 index 0000000..488c24f --- /dev/null +++ b/dsad-2/outputPS5.txt @@ -0,0 +1,6 @@ +Maximum Profit(Divide & Conquer): 43 +Day to buy: 7 +Day to sell: 11 +Maximum Profit(Iterative Solution): 43 +Day to buy: 7 +Day to sell: 11 diff --git a/dsad/A1_PS5_DC_21.py b/dsad/A1_PS5_DC_21.py index 69883cd..500eacf 100644 --- a/dsad/A1_PS5_DC_21.py +++ b/dsad/A1_PS5_DC_21.py @@ -1,13 +1,14 @@ #!/usr/bin/env python3 -import re import copy +import re + class PatientRecord: """ Stores patient info. """ def __init__(self, age, name, Pid): - self.PatId = str(Pid) + str(age).rjust(2,'0') + self.PatId = str(Pid) + str(age).rjust(2, '0') self.name = name self.age = age self.left = None @@ -17,6 +18,69 @@ def __str__(self): """ debugging aid """ return "{}, {}, {}".format(self.name, self.age, self.PatId) + +def next_patient_banner(p): + """ Generate 'Next Patient' message. + + Return info about the next patient. + """ + + if p is None: + return "Patient queue is empty.\n" + + return """---- next patient --------------- +Next patient for consultation is: {}, {} +---------------------------------------------- +""".format(p.PatId, p.name) + + +def _swap(n1, n2): + """ Swap two nodes. """ + + # It is easier to swap the values than all the links. + n1.age, n2.age = n2.age, n1.age + n1.name, n2.name = n2.name, n1.name + n1.PatId, n2.PatId = n2.PatId, n1.PatId + + +def _max(node1, node2): + """ Return the node having higher age value, + or None if both nodes do not exist. + """ + + if node1 is None and node2 is None: + return None + + if node1 is None: + return node2 + if node2 is None: + return node1 + + if node1.age > node2.age: + return node1 + else: + return node2 + + +def read_in2(): + """ Read the second input file, line by line. """ + + infile = 'inputPS5b.txt' + with open(infile, "r") as f: + for line in f: + yield line + return + + +def write_out2(file): + """ Write/append to second output file. """ + + outfile = 'outputPS5.txt' + with open(outfile, "a+") as f: + f.write(file) + return + + class ConsultQueue: """ Build the Consult Queue as a max heap tree. For every new patient, the patient id is generated and @@ -24,11 +88,10 @@ class ConsultQueue: """ initial_pid = pid = 1000 # patient counter (initial value.) - register = dict() # provide easy mapping b/w patId and patient node. - queue = list() # stores the max heap tree - queue2 = list() # duplicate list, preserves the original heap for reconstruction. - root = None # heap tree's root - + register = dict() # provide easy mapping b/w patId and patient node. + queue = list() # stores the max heap tree + queue2 = list() # duplicate list, preserves the original heap for reconstruction. + root = None # heap tree's root def registerPatient(self, name, age): """ Register a patient node. @@ -38,12 +101,11 @@ def registerPatient(self, name, age): Return newly added patient node. """ - patid = self._generate_pat_id(name, age) + patid = self._generate_pat_id() patient = PatientRecord(age, name, patid) self.register[patid] = patient return self.enqueuePatient(patid) - def enqueuePatient(self, PatId): """ Add patient node to max heap. @@ -53,7 +115,6 @@ def enqueuePatient(self, PatId): patient = self.register[PatId] return self._heap_add(patient) - def nextPatient(self): """ Remove next patient from the heap. @@ -62,12 +123,11 @@ def nextPatient(self): if self.root is not None: # dequeue root and heapify the tree again. - return self._dequeuePatient(self.root.PatId) + return self._dequeuePatient() else: return None - - def _dequeuePatient(self, patid=None): + def _dequeuePatient(self): """ Remove next patient from the heap. Argument: patId (unused, as we do not remove arbitrary patient node but always the one from the heap's root.) @@ -77,7 +137,6 @@ def _dequeuePatient(self, patid=None): """ return self._heap_remove() - def new_patient_banner(self, p): """ Generate 'New Patient' message. Return info about the new patient. @@ -90,23 +149,7 @@ def new_patient_banner(self, p): ---------------------------------------------- """.format(p.name, p.age, p.PatId, self._heap_items().rstrip()) - - def next_patient_banner(self, p): - """ Generate 'Next Patient' message. - - Return info about the next patient. - """ - - if p is None: - return "" - - return """---- next patient --------------- -Next patient for consultation is: {}, {} ----------------------------------------------- -""".format(p.PatId, p.name) - - - def _generate_pat_id(self, age, name): + def _generate_pat_id(self): """ Generate patient id in form. Return Patient Id. @@ -117,33 +160,6 @@ def _generate_pat_id(self, age, name): patid = str(self.pid).rjust(4, '0') return patid - - def _swap(self, n1, n2): - """ Swap two nodes. """ - - # It is easier to swap the values than all the links. - n1.age, n2.age = n2.age, n1.age - n1.name, n2.name = n2.name, n1.name - n1.PatId, n2.PatId = n2.PatId, n1.PatId - - def _max(self, node1, node2): - """ Return the node having higher age value, - or None if both nodes do not exist. - """ - - if node1 is None and node2 is None: - return None - - if node1 is None: - return node2 - if node2 is None: - return node1 - - if node1.age > node2.age: - return node1 - else: - return node2 - def _heap_add(self, node): """ Add a node to max heap tree and heapify the tree. """ @@ -154,7 +170,7 @@ def _heap_add(self, node): return node # if heap is not-empty, find the (expected) parent of the new node. - parent = self.queue[len(self.queue) // 2 -1] + parent = self.queue[len(self.queue) // 2 - 1] # connect the new node to parent's left/right, whichever available. if parent.left is None: @@ -179,13 +195,13 @@ def _heap_remove(self): # before swapping, remove parent->last_node pointer. last_node = self.queue[-1] - parent = self.queue[len(self.queue)//2 -1] + parent = self.queue[len(self.queue) // 2 - 1] if parent.left is last_node: parent.left = None else: parent.right = None - self._swap(self.root, last_node) + _swap(self.root, last_node) root = self.queue.pop(-1) # Tree can be empty here. @@ -202,15 +218,15 @@ def _heapify_bottom_up(self, node): Return the original node. """ - parent_pos = len(self.queue) // 2 -1 + parent_pos = len(self.queue) // 2 - 1 parent = self.queue[parent_pos] while parent is not None and parent.age < node.age: - self._swap(parent, node) - node = parent # move up and compare again + _swap(parent, node) + node = parent # move up and compare again # calculate current node's parent's index, special handling for root. - parent_pos = parent_pos // 2 - 1 + parent_pos = (parent_pos-1) // 2 if parent_pos < 0: parent_pos = 0 parent = self.queue[parent_pos] @@ -228,11 +244,11 @@ def _heapify_top_down(self): node = self.root while node is not None: - child = self._max(node.left, node.right) + child = _max(node.left, node.right) # if current node's age value is smaller than one of it's child, # swap with larger child. if child is not None and node.age < child.age: - self._swap(node, child) + _swap(node, child) node = child else: break @@ -261,7 +277,6 @@ def _heap_items(self): return output - def read_in1(self): """ Read initial input file and register the patients. """ @@ -289,26 +304,8 @@ def write_out1(self): f.write(text) return - def read_in2(self): - """ Read the second input file, line by line. """ - - infile = 'inputPS5b.txt' - with open(infile, "r") as f: - for line in f: - yield line - return - - def write_out2(self, str): - """ Write/append to second output file. """ - - outfile = 'outputPS5.txt' - with open(outfile, "a+") as f: - f.write(str) - return - def main(): - # create the initial queue from infile1 cq = ConsultQueue() cq.read_in1() @@ -317,7 +314,7 @@ def main(): cq.write_out1() # enqueue new patients from infile2. - for line in cq.read_in2(): + for line in read_in2(): # we expect either a 'New patient' with name/age info # or the 'Next Patient' command if re.match('^newPatient:', line): @@ -327,10 +324,10 @@ def main(): age = int(age) patient = cq.registerPatient(name, age) - cq.write_out2(cq.new_patient_banner(patient)) + write_out2(cq.new_patient_banner(patient)) elif re.match('^nextPatient', line): patient = cq.nextPatient() - cq.write_out2(cq.next_patient_banner(patient)) + write_out2(next_patient_banner(patient)) main() diff --git a/dsad/ASSIGNMENT1_PUN_B1_G21.zip b/dsad/ASSIGNMENT1_PUN_B1_G21.zip new file mode 100644 index 0000000..2fd20f4 Binary files /dev/null and b/dsad/ASSIGNMENT1_PUN_B1_G21.zip differ diff --git a/dsad/analysisPS5.txt b/dsad/analysisPS5.txt new file mode 100644 index 0000000..b00ce00 --- /dev/null +++ b/dsad/analysisPS5.txt @@ -0,0 +1,223 @@ +Analysis of Assignment 5 +======================== + + +Program logic +-=-=-=-=-=-=- + + Populating Initial ConsultQueue + -------------------------------- + + The programs implements a priority queue via a max-heap tree, which is + built one node at a time with the given initial list of patients. The + tree is heapified using the bottom-up approach, each time a patient node + is inserted. + + The max-heap is implemented with a python list, which makes it easier to + reach to any node's parent using its index. The list also allows for + arbitrarily large number of nodes to be inserted, the upper bound on the + number of nodes is limited only by system's available memory. + + + Refreshing the Queue + -------------------- + + Once the heap tree is populated with the given list of initial patients, + the queue is refreshed, which means the heap tree is printed in + non-increasing order of patient's age. Printing a heap tree requires + that the elements of the tree are removed one by one, with max-heap + being heapified after every deletion. The deletion uses the strategy of + swapping the last node with heap tree's root (patient node with highest + age), and then heapifying the tree using top-down heapify approach. + The original root node is removed from the tree (python list) and the + process is repeated till the queue is empty. + + Since the printing of sorted ConsultQueue requires emptying out of the + original queue, we need to keep a copy of the ConsultQueue for later + restoration of the heap-tree, so that the tree can be refreshed / + printed again, once a new patient is registered. + + + Patient Registration + -------------------- + + Every time a new patient is added to the ConsultQueue, the heap-tree is + heapified using the bottom-up heapify approach. + + + Next Patient + ------------ + + A nextPatient command deletes the patient node from the root of the heap + tree using top-down heapify approach. + + + +Time complexity +-=-=-=-=-=-=-=- + + Building initial ConsultQueue + ----------------------------- + + Initially, if the number of patients having arrived at clinic is 'm' the + time complexity to build the initial ConsultQueue is: + + O(m * log m) + + Upon building the initial ConsultQueue, it needs to be refreshed / printed + *one time*, incurring an additional: + + O(m * log m) complexity. + + + Subsequent New Patients + ----------------------- + + If there are 'n' newPatient commands ('n' new patient arrive + subsequently) while none of the original 'm' patients are removed from + the priority queue, the total size of the max-heap grows to n + m. The + time complexity of insertion for 'n' new nodes is: + + O(n * log (m+n)) + + + ConsultQueue refresh + -------------------- + + However, as the ConsultQueue needs to be refreshed and restored after + each new patient node is inserted, the complexity for refreshing + ConsultQueue *once* is: + + Time complexity of sorting (m+n) elements + Time complexity of backing + up original queue + Time complexity of restoring the queue. + + = O((m+n) * log(m+n)) + O(m+n) + O(1) = O((m+n) * + log(m+n)) + + For 'n' newPatient commands, the complexity becomes: O(n* (m+n) * + log(m+n)) + + + Next Patient + ------------ + + A patient node is deleted, and tree is heapified. + + The heapification is done in: O (log (m+n)) time, assuming the total + queue size is (m+n). + + If there are 'p' nextPatient commands, the complexity of deleting 'p' + nodes and heapifying the tree becomes: + + O(p * log(m+n)) + + nextPatient command does not require the queue to be printed, so no + additional complexity is incurred. + + + --------------------- + Total Time Complexity + --------------------- + + The total time complexity can be obtained by summing up all the + individual time complexities above: + + 2*O(m * log m) + O(n * (m+n) * log(m+n)) + O(p * log(m+n)) + + with m, n and p being arbitrarily large numbers approaching N, the + upper-bound for the total time complexity can be given by: + + O(N^2 * log(N)) + --------------- + + +Space complexity +-=-=-=-=-=-=-=-= + + The program uses the following structures to store / implement the max + heap tree as a priority queue. + + queue - A python list structure that stores the max-heap tree. + + Space complexity incurred by 'queue' structure is: + + O(m+n) + here, 'm' being the count of initial patients, and 'n' + patients are added subsequently. + + + queue2 - Another python list structure to back up the 'queue' contents + before refreshing, and restore the original heap tree subsequently. + + Space complexity incurred by 'queue2' structure is also: + + O(m+n) + + + register - A python dict structure to map the patient id to patient + nodes. This one is *not* required if we choose to pass patient info + using PatientRecord node, instead of patient id. However, as the + skeleton program of problem expects to pass patient-id to + _enqueuePatient instead of PatientRecord, we need a mapping + structure to get the correct PatientRecord node. + + Space complexity incurred by 'register' structure is also: + + O(m+n) + + + ---------------------- + Total space Complexity + ---------------------- + + The total space complexity can be obtained by summing up all the + individual space complexities above: + + 3 * O(m + n) = O(m + n) + + which can be considered as + + O(N) + N being the total number of the patients. + + +Further Optimization and Takeaways +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + - A max heap tree is not a suitable structure where one needs to print + the sorted list frequently. As the full sorted list can only be obtained + after removing all elements one by one, this incurs O(n*logn) + complexity for every print operation. + A structure such as a binary search tree is a better fit in such cases, + which can provide a sorted list in O(n) time, thus reducing the total + time complexity for 'm' sorted-print operations to + O(mn) instead of the current O(mn logn). + + - max heap can be built in O(n) time complexity when all the initial n + nodes are given. This approach uses only non-leaf nodes for + heapification, starting from the lowest level of the initial level-order + tree. + The current implementation builds the tree one element at a time, + and incurs O(n logn) for heap building. + This can be improved. + + - An ideal solution to the given problem would be by making use of an + *additional* binary search tree for printing the sorted list. This comes + at the cost of an additional O(n) space complexity. + + In this case - + + * Each new node would be added to both the heap tree and BST with + O(logn) time complexity. + + * A deletion would cause the node to be deleted from both heap and + BST with O(logn) time complexity. + + * Printing a list would print the sorted list by traversing BST only, + with O(n) time complexity, thus 'm' print operations would require O(mn) + complexity. + + * Additionally, we would not require a backup queue to preserve original + heap tree, as the sorted print happens only through BST; thereby + canceling out the added space complexity of maintaining a BST. + diff --git a/dsad/outputPS5.txt b/dsad/outputPS5.txt new file mode 100644 index 0000000..f8f500e --- /dev/null +++ b/dsad/outputPS5.txt @@ -0,0 +1,42 @@ +---- initial queue --------------- +No of patients added: 3 +Refreshed queue: +100160, Surya +100327, Rishi +100214, Ajay +---------------------------------------------- +---- new patient entered --------------- +Patient details: John, 55, 100455 +Refreshed queue: +100160, Surya +100455, John +100327, Rishi +100214, Ajay +---------------------------------------------- +---- next patient --------------- +Next patient for consultation is: 100160, Surya +---------------------------------------------- +---- new patient entered --------------- +Patient details: Pradeep, 45, 100545 +Refreshed queue: +100455, John +100545, Pradeep +100327, Rishi +100214, Ajay +---------------------------------------------- +---- next patient --------------- +Next patient for consultation is: 100455, John +---------------------------------------------- +---- next patient --------------- +Next patient for consultation is: 100545, Pradeep +---------------------------------------------- +---- new patient entered --------------- +Patient details: Sandeep, 60, 100660 +Refreshed queue: +100660, Sandeep +100327, Rishi +100214, Ajay +---------------------------------------------- +---- next patient --------------- +Next patient for consultation is: 100660, Sandeep +----------------------------------------------