Wednesday, August 10, 2016

Objective : Solvea 15-puzzle program using a realtime search algorithm.  
The 15-puzzle problem is some arrangement of numbers 1 to 15 in a 4 x 4 grid with 16 square blocks labeled 1 to 15 and one blank square. The blocks need to be arranged so that they are in order from any starting configuration. 

We described the A* algorithm yesterday.
Now, we use a real time algorithm as described by Ian Parberry. It is designed using both greedy and divide-and-conquer techniques. 
The algorithm is generalized for (n^2-1) grid puzzles. 

The algorithm is described as follows: 
procedure puzzle(n) 
if n == 3 then solve by brute force else 
          use a greedy algorithm to put the first row and column into place 
          call puzzle(n-1) to solve remaining rows and columns. 

Step 2 above places tiles in the first row ( 1 <=k <=n ) into place at locations (1, k) followed by  
(2 <= k <=n) tiles into place at locations (k,1) for 2 <=k <= n into place, one at a time. 

The implementation looks something like this: 

Void Solve(Board<Location> b, Board<Location> goal, int n, Location blank) 
{ 
For (int k = 1; k <= n/2; k++) 
{ 
Var tile = goal[1,k]; 
Var location = getPosition(b, tile); 
If (location.row > 1 && location.col > N/2) 
{ 

If (k == 1)  
    Move_the_blank_to_right_adjacent(1,2,blank.row, blank.col); 
else  
    Move(2,k-1,blank.row, blank.col); 

If (k> 1) 
Move_the_blank_to _right_adjacent(1,k+1, 2,k-1) 

// move the target tile diagonally to nearest axis 
If (location.row-1 > location.col-1) 
            Move_target_tile_to_goal_col(1,k,ref  location.row, ref location.col) 
Else 
            Move_target_tile_to_goal_row(1,k, ref location.row, ref location.col) 



// location is updated by reference 
//move the target tile horizontally  or vertically 
Move_target_tile_to_goal(1,k, ref location.row, ref location.col) 
         // assert( location.row ==1 || location.col == k); 

}else{ 
 // similar 
} // end else 


} // end for 
} 



To move a tile vertically up, the blank must move from its right anticlockwise to the position right above the tile so that the tile can take its place. 
To move a tile horizontally to the left, the blank must move anticlockwise to the tile’s left so that the tile can take its place. 
To move a tile diagonally to the left, the blank must move anticlockwise to the position right above the tile, so that he tile can take its place and the blank can come down. From this position, the blank has to move clockwise until it is to the adjacent left of the tile so that the tile can take its place.



Location GoAntiClockwiseAround(Location center, int n, int steps)
{
var current = center;
for (int i = 0; i < 8 && steps; i++)
{
switch(i)
{
case 0:
    if (center.row - 1 > 0){
       current.row = center.row - 1;
       current.col = center.col;
       steps--;
    }
    break;
case 1:
    if (center.row  - 1 > 0 && center.col - 1 > 0){
       current.row = center.row - 1;
       current.col = center.col - 1;
       steps--;
    }
    break;
case 2:
    if (center.col -1 > 0){
       current.row = center.row;
       current.col = center.col - 1;
       steps--;
    }
    break;
case 3:
    if (center.row + 1 < n && center.col - 1 > 0){
       current.row = center.row + 1;
       current.col = center.col - 1;
       steps--;
    }
    break;
case 4:
    if (center.row + 1 < n){
       current.row = center.row + 1;
       current.col = center.col;
       steps--;
    }
    break;
case 5:
    if (center.row + 1 < n && center.col + 1 < n){
       current.row = center.row + 1;
       current.col = center.col + 1;
       steps--;
    }
    break;
case 6:
    if (center.col + 1 < n){
       current.row = center.row;
       current.col = center.col + 1;
       steps--;
    }
    break;
case 7:
    if (center.row - 1 > 0 && center.col + 1 < n){
       current.row = center.row - 1;
       current.col = center.col + 1;
       steps--;
    }
    break;
default:
   break;
}
}
return current;
}

Tuesday, August 9, 2016

Objective : Solve a 8-puzzle program using the A* search algorithm. 


The 8-puzzle problem is some arrangement of numbers 1 to 8 in  a 3 x 3 grid with 8 square blocks labeled 1 to 8 and one blank square. 
The blocks will be arranged so that they are in order. 


The A* algorithm is like this: 
Take a snapshot of the puzzle as it appears initially and put it in the priority queue.  
We keep track of previous snapshot and current snapshot.  
The current snapshot is the one in the priority queue and the previous initially is null. 
We remove the snapshot with the minimum priority and insert into it all the neighbouring snapshots.
A neighbouring snapshot is one with that can be reached in one move. 
The priority for a snapshot is found by counting the number of blocks in the wrong position,  
plus the number of moves made so far to get to the snapshot. 
The minimum number of moves must at least be the priority of a snapshot. 
We repeat the procedure until desired goal snapshot is found. 




The priority or cost of a particular state is described in terms of three parameters
f, g and h
g is the cost it took to get to that square and is the number of snapshots we passed from the start
h is our guess to how much it will take to reach the goal and is counted as the number of squares that are not in their place
f = g + h
A star is also called the best path algorithm
The algorithm is described this way:
var open = new List<8Puzzle>();
var closed = new List<8Puzzle>();
void BestPath(8Puzzle start, 8Puzzle goal, ref List<8Puzzle> open, ref List<8Puzzle> closed)
{
open.add(8Puzzle);
while (open.Count > 0)
{
     var q = open.min();
     open.remove(q);
     var neighbors = getNeighbors(q)
     foreach (var neighbor in neighbors){
             if (neighbor == goal) return;
             neighbor.parent = q
             neighbor.g = q.g + distance(q, neighbor)
             neighbor.h = distance(goal, neighbor)
             neighbor.f = neighbor.g + neighbor.h
             
             var seen = open.First( x == neighbor);
             if (seen != null && seen.f < neighbor.f) continue;
             seen = closed.First(x == neighbor);
             if (seen != null && seen.f < neighbor.f) continue;
             open.add(neighbor)
           }
     closed.Add(q);
}
}

Monday, August 8, 2016

Today we continue our discussion of the  paper titled "Pelican: a  building block for exascale cold data storage". Pelican treats a group of disks as a single schedulable unit. Resource restrictions such as power consumption, vibrations and failure domains are expressed as constraints over these units.
With the help of resource constraints and scheduling units, Pelican aims to be better than its over provisioned counterpart racks using computations in software stacks.
We were discussing the evaluation of Pelican and listing out the metrics chosen. To compare the evaluations, a simulator was used in addition to the Pelican hardware rack and the simulator and the rack were cross validated. It was configured in such a way that the prototype Pelican rack hardware matched the simulator. Traditionally, simulating hard disk-based storage accurately is very hard due to the complexity of the mechanical hard drives and their complex control software that runs on the drive. We were discussing the completion time. The completion time increased linearly by the order of 3 for an increase by 64 times the number of requests. The simulator and the rack performed very much like each other. 
Another metric used was the average reject rate.  This measures the requests that are not serviced because the queues are full and the workload is higher than what Pelican can service. It represents the average fraction of requests rejected. In all the experiments, the average incoming rate is 8 requests per second because the NIC card is the bottleneck.
Pelican was also measured for throughput.
Throughput was the same between tge simulator and the rack. This gave more confidence on the results. For throughput, the impact of spinning up disks is small

#puzzle
There are 5 pirates and they have to split 100 gold coins between themselves. The pirates have seniority levels from A to E. The rules of distribution are : 
The most senior pirate proposes a distribution of coins.
All pirates vote on whether to accept the distribution.
If the distribution is accepted, the coins are disbursed and the game ends.
If not, the proposer is thrown and dies, and the next most senior pirate makes a new proposal to begin the system again.

In case of a tie vote the proposer can has the casting vote
Rules every pirates follows.
Every pirate wants to survive

Given survival, each pirate wants to maximize the number of gold coins he receives.
Solution : The answer is 98 coins.
This follows from a tail recursion
If only D and E are there, it will be a distribution of (100, 0) because D has a casting vote
If only C, D and E are there, it will be a distribution of (99,0,1) because C can get enough votes
If B, C, D and E are there, it will be a distribution of (99,0,1,0) because B can get enough votes
if A, B, C, D and E are there, it will be a distribution of (98, 0, 1, 0, 1) to get enough votes.
#codingexercise
Add two numbers without using arithmetic operators
// half adder
int Add (int x, int y)
{
while (y != 0)
{
    int carry = x & y;
    x = x ^ y;
    y = carry  << 1;
}
Return x
}
eg:
add (011, 101)
S, C
110 , 010
100, 100
000, 1000
1000, 000

Similarly,
int Subtract (int x, int y)
{
while (y != 0)
{
    int borrow = (~x)  & y;
    x = x ^ y;
    y = borrow << 1;
}
Return x
}

Sunday, August 7, 2016

Today we continue our discussion of the  paper titled "Pelican: a  building block for exascale cold data storage". Pelican treats a group of disks as a single schedulable unit. Resource restrictions such as power consumption, vibrations and failure domains are expressed as constraints over these units.
With the help of resource constraints and scheduling units, Pelican aims to be better than its over provisioned counterpart racks using computations in software stacks.
We were discussing the evaluation of Pelican and listing out the metrics chosen. To compare the evaluations, a simulator was used in addition to the Pelican hardware rack and the simulator and the rack were cross validated. It was configured in such a way that the prototype Pelican rack hardware matched the simulator. Traditionally, simulating hard disk-based storage accurately is very hard due to the complexity of the mechanical hard drives and their complex control software that runs on the drive. We were discussing the completion time. The completion time increased linearly by the order of 3 for an increase by 64 times the number of requests. The simulator and the rack performed very much like each other. 
The next metric used was time to first byte.  This is the time between a request being issued by a client and the first data byte being sent to the client. This includes the queuing delay and any disk spin up and volume mount delays By its nature, the factors that affect the completion time also affect the time to first byte. Consequently we expect the graph to be linear as well and indeed it turned out to be very similar to the graph for the completion time.
The Service time was another metric used. This is the time from when a request is dequeued by the scheduler to when the last byte associated with the request is transferred. This includes delays due to spinning up disks and the time taken to transfer the data but excludes the queuing delay. As such it focuses on the scheduler status updates to the task. It differs from the completion time in that it excludes the queuing delay and focuses only on the performance of the disks. The charts for service time is therefore different from that for completion time or the time to first byte. The service time dropped from 15 sec to 5 sec as requests increased 64 times for both the simulator and the rack.  This showed that the scheduler does better with increasing loads  and that the time to spin up disks is reduced while remaining within the constraints.
#codingexercise
A person has 3000 bananas and a camel. The person wants to transport maximum number of bananas to a destination which is 1000 KMs away, using only the camel as a mode of transportation. The camel cannot carry more than 1000 bananas at a time and eats a banana every km it travels. What is the maximum number of bananas that can be transferred to the destination using only camel (no other mode of transportation is allowed)
The answer is 533 1/3 bananas.
The camel cannot come back if it makes a straight run to the destination. There will not be any bananas to unload at the destination and there won't be any bananas left to eat so that the camel can return.
The maximum distance the camel can travel is 500 kms for the thousand bananas loaded on it. Therefore there are intermediate stations to stop before reaching the market. Let us say these stations are A,B, C  ... in the order from source to destination.
To unload 3000 bananas in max hypothetical unload of 1000 bananas each three forward trips and two return trips are at least needed. The first segment must at least have five trips, the next segment must be less than this five and for a longer distance in order to save bananas and further decreasing from that point on. So we have 5, 3, 1 number of trips and the cost of each segment can be considered as 5 bananas / km, 3 bananas per km and 1 banana per km to the destination.
The camel can carry at most 2000 bananas from point A and 1000 bananas from point B to destination.
3000 - 5 PA = 2000   => PA = 200 kms
2000 - 3 AB = 1000   => AB = 333 + 1/3 kms
BM = 1000-200-333 1/3 = 466 2/3 kms
The camel arrives at the destination with 533 1/3 bananas.

Saturday, August 6, 2016

Today we continue our discussion of the  paper titled "Pelican: a  building block for exascale cold data storage". Pelican treats a group of disks as a single schedulable unit. Resource restrictions such as power consumption, vibrations and failure domains are expressed as constraints over these units.
With the help of resource constraints and scheduling units, Pelican aims to be better than its over provisioned counterpart racks using computations in software stacks
Pelican uses resources from a set of resource domains which is a subset of disks. Pelican proposes a data layout and IO scheduling algorithms by expressing these resource domains as constraints over the disks. We were discussing evaluation of Pelican and the Poisson process to generate a range of workloads Most of these workloads focused on read request because the write requests are offloaded to other storage tiers, we assume that servicing read requests is the key performance requirement for Pelican. The read requests are randomly distributed across all the blobs stored in the rack. Requests operate on a blob size of 1 GB. The evaluation used the following metrics:
Completion time - this is the end to end time between the request initiation by the client and the last data received. It captures the queuing delay, spin up latency, and the time to read and transfer data. The completion time increased linearly with the number of requests for both the rack and the simulator.  This was after the simulator and the rack were cross validated. It was configured in such a way that the prototype Pelican rack hardware matched the simulator. It goes to show that both the sequential file read and the disks being spun up take a toll on the completion time  Further the disks are being spun up only one at a time and only one disk spinning per tray rather than two disks spinning up. The completion time increased by the order of 3 for an increase by 64 times the number of requests. This covered the range of the most practical range of workload that Pelican would typically be used for. It was also clear that the simulator could be run for extrapolation with just as much reliability as the pelican rack hardware.  Consequently the completion time graph gave satisfying results in terms of predictability. The distribution of workload and the effectiveness of Pelican was clear from this linear plot.
#codingexercise
You are given partial information of a binary tree: for each node, its id, and the sum of the ids of its children. This sum is 0 if the node is a leaf, and if the node has just one child, then it is equal to the child's id. Given this, you are asked to output ids of all possible roots of such a tree, given that such a tree does exist.
int GetRootId(List<int>id, List<int>sum)
{
assert(id.count == sum.count);
assert(id.all(x => x > 0));
assert(sum.all(x=>x > 0));
int root = 0;
for (int i =0; i<n; i++)
{
root +=  id[i] - sum[i];
}
return root;
}

Return the square root of a number
Double SqRt (int n)
{
Double g = n/2;
Double y = n/g;
While(abs (y-g) > 0.001)
{
   g = (g + n/g) /2;
   y = n / g;
}
Return y;
}

Friday, August 5, 2016

Today we continue our discussion of the  paper titled "Pelican: a  building block for exascale cold data storage". Pelican treats a group of disks as a single schedulable unit. Resource restrictions such as power consumption, vibrations and failure domains are expressed as constraints over these units.
With the help of resource constraints and scheduling units, Pelican aims to be better than its over provisioned counterpart racks using computations in software stacks
Pelican uses resources from a set of resource domains which is a subset of disks. Pelican proposes a data layout and IO scheduling algorithms by expressing these resource domains as constraints over the disks. We were discussing evaluation of Pelican.
Pelican was measured under different load regimes. The disk throughput was measured using a quiescent system. Seeks are simulated by including a constant latency of 4.2 ms for all disk accesses and it was found that seek latency has negligible impact on performance. It was also found that the latency of spinning the disk up and mounting the volume heavily dominate over seek time. The distribution for mount delays was widely affected by the load on the system. 
Pelican was compared with a system denoted by FP that was subject to no resource constraints. The disks were never spun down but the same topology was used.  Pelican partitions the disks into 48 groups whereas in FP all 48 groups could be concurrently accessed. Reads are done at full throughput because the stripe stacks are contiguous on disk.
Pelican supports a wide variety of workloads. A full range of workloads is covered by parameters representing characteristics and using a Poisson process with an average arrival rate of 1 / lambda. The Poisson process allows us to model random events along a real line using a single parameter which in this case is made to vary with lambda from 0.125 to 16. The average request rate per second is shown  rather than the lambda value because this makes the results clear. The workloads are all such that Pelican can focus on servicing read requests which are randomly distributed across all the blobs stored in the rack.

#codingexercise

Check if a given array is a pre-order traversal of a binary search tree

bool IsPre(List<int>nums)
{
var stk = new Stack<int>();
int root = INT_MIN;
for (int i = 0; i < nums.Count; i++)
{
    if (nums[i]  < root)
         return false;
   while (!stk.empty() && s.top() < nums[i])
   {
         root = stk.top()
         stk.pop();
   }
   stk.push(nums[i]);
}
return true;
}
50 30 35 70 80
35 30 80 70 50
The same linear scan above can be applied to finding the next greater element for every element in an array.

void GetNextGreater(List<int> arr)
{
if (arr.count == 0) return;
int element, next;
var stk = new Stack();
stk.push(arr[0]);
for (int I = 1; I < arr.Count; i++)
{
next = arr[I];
If (isEmpty(stk) == false)
{
element = stk.pop();
while (element < next)
{
Console.Write("{0} next {1}", element, next);
if (isEmpty(stk) == true) break;
element = stk.pop()
}
if (element > next)
    stk.push(element)
}
stk.push(next)
}
while (stk.empty() == false)
{
element = stk.pop()
next = -1;
Console.Write("{0} next {1}", element, next);
}
}

The same scan that holds true for preorder check does not hold true for post order because the root is no longer the first encountered that will be greater than both the left and right in a BST.
So the solution would be to reverse scan the array
bool IsPost(List<int>nums)
{
var stk = new Stack<int>();
int root = INT_MIN;
for (int i = nums.Count - 1; i> 0; i--)
{
   while (!stk.empty() && s.top() > nums[i])
   {
         root = stk.top()
         stk.pop();
   }
    if (nums[i]  < root)

         return false;
   stk.push(nums[i]);
}
return true;
}

50 30 35 70 80
35 30 80 70 50

Thursday, August 4, 2016

Today we continue our discussion of the  paper titled "Pelican: a  building block for exascale cold data storage". Pelican treats a group of disks as a single schedulable unit. Resource restrictions such as power consumption, vibrations and failure domains are expressed as constraints over these units.
With the help of resource constraints and scheduling units, Pelican aims to be better than its over provisioned counterpart racks using computations in software stacks
Pelican uses resources from a set of resource domains which is a subset of disks. Pelican proposes a data layout and IO scheduling algorithms by expressing these resource domains as constraints over the disks. We were discussing evaluation of Pelican.
Pelican was measured under different load regimes. The disk throughput was measured using a quiescent system. Seeks are simulated by including a constant latency of 4.2 ms for all disk accesses and it was found that seek latency has negligible impact on performance. It was also found that the latency of spinning the disk up and mounting the volume heavily dominate over seek time. The distribution for mount delays was widely affected by the load on the system. 


We were analyzing the charts from the evaluation run.we said the spin up and unmount delay are not affected by load and have more or less a uniform distribution because they affect all the disks and are one time only. This is different for mount delays where the higher the workload the higher the chance of a disk being a straggler.


#codingexercise
There are n pairs of 2n people. All these 2n persons are arranged in random fashion.Find the minimum number of swaps required to arrange these pairs such that all pairs become adjacent to each other.
Notice this has a greedy choice property in terms of costs as the number of pairs
The cost to pair the first two elements if they are already a pair is zero.
The cost to pair the first two element if they are not is the minimum of the costs to find the partner for the first element and to find the partner for the second element
Once we found the minimum cost for the first we do the same for the next pair.
Each time we revert the changes made so we can find the cost for the next pair as it appears in the given order.

int GetMinSwaps(List<int> pairs, List<int>num, List<int>index, int start)
{
var n = num.Count;
if (start> n) return 0;
if (pairs[num[start]]  == num[start+1])
    return GetMinSwaps(pairs, num, index, start+2);

int select = num[start+1]
int pairindex = index[pairs[num[start]]];
int partner = num[pairindex];
Swap(num[start+1], partner)
UpdateIndex(index, select, start+1, partner, pairindex);
int firstcost = GetMinSwaps(pairs, num, index, start+2);

swap(num[start+1], partner);
UpdateIndex(index, select, pairindex, partner, start+1);

int secondindex = index[pairs[num[start+1]]];
int second = nums[secondindex];
swap(nums[start], second);
UpdateIndex(index, second, secondindex, nums[start], start);
int secondcost = GetMinSwaps(pairs, num, index, start+2);

swap(nums[start], second);
UpdateIndex(index, second,start, nums[start], secondindex);

return 1 + min(firstcost, secondcost);


}
Void updateindex(list<int> index, int first, int firstindex, int second, int secondindex)
{
Index[firstindex] = first;
Index[secondindex]=second;
}