import java.util.*; import java.awt.*; import java.applet.*; import java.lang.Math.*; import List; import ListElem; import C_component; import Permutation; import Reversal; public class OVGraph { // Data members private Permutation m_permutation; private boolean m_all_components_oriented; private int[] m_components_indexes; private C_component[] m_components; private int[] m_CR; private int m_hurdles_num; private Permutation original_permutation; // constructor public OVGraph(Permutation permutation) throws Exception { m_permutation = permutation; makeComponents(); } /* **************** GENERAL AUXILARY METHODS ************* */ public int getPosition(int index) throws Exception { return m_permutation.getPosition(index); } public int getIndex(int position) throws Exception { return m_permutation.getIndex(position); } private int getNeighbourIndex(int index) { if((index % 2) == 0) return (index + 1); else return (index - 1); } // Find the index of the edge by one of its endpoints indexes public int getVertexIndexByIndex(int index) { return (index / 2); } // Find the index of the edge by the position of one of its endpoints public int getVertexIndexByPosition(int position) throws Exception { return getVertexIndexByIndex(this.getIndex(position)); } public int getLeftEndpoint(int vertex_index) throws Exception { int even = 2 * vertex_index; int odd = 2 * vertex_index + 1; int[] range = m_permutation.getPositions(even, odd); return range[0]; } public int getRightEndpoint(int vertex_index) throws Exception { int even = 2 * vertex_index; int odd = 2 * vertex_index + 1; int[] range = m_permutation.getPositions(even, odd); return range[1]; } // Get the neighbour (by black edge) private int getBlackNeighbour(int index) throws Exception { int position = getPosition(index); if((position % 2) == 0) return getIndex(position + 1); else return getIndex(position - 1); } // Check if a vertex (BP graph edge) is oriented public boolean isOriented(int vertex_index) throws Exception { if(isBreakpoint(vertex_index) == false) return false; int even = 2 * vertex_index; int odd = 2 * vertex_index + 1; int temp = getPosition(even) - getPosition(odd); return((temp % 2) == 0); } // Check if a vertex (BP graph edge) is not oriented private boolean isUnoriented(int vertex_index) throws Exception { return (isBreakpoint(vertex_index) && !isOriented(vertex_index)); } // Check weather a pair of vertices is a breakpoint public boolean isBreakpoint(int vertex_index) throws Exception { int even = 2 * vertex_index; int odd = 2 * vertex_index + 1; int temp = getPosition(odd) - getPosition(even); return(java.lang.Math.abs(temp) != 1); // in a non-breakpoint this number will be 1 since even,odd appear consequently in the permutation } // Return the number of vertices public int getNumOfVertices() { return this.m_permutation.getSize() / 2; } public void reversal(Reversal reversal) throws Exception { m_permutation.reversal(reversal); m_components = null; } public Permutation getPermutation() { return m_permutation; } public C_component[] getComponents() throws Exception { if(m_components == null) this.makeComponents(); return this.m_components; } // Get an array of the oriented vertices (by indexes) private int[] getOrientedVerticesByLeftOrder() throws Exception { int oriented_counter = 0; int vertices_num = this.getNumOfVertices(); int permutation_size = m_permutation.getSize(); boolean[] orientations = new boolean[vertices_num]; // Check the orientation of all the vertices from left to right int vertex_index; for(vertex_index=0; vertex_index= components[neighbour_vertex_index]) throw new Exception("OVGraph::workOnEdges - unexpected event, DFS failed"); components[neighbour_vertex_index] = components[vertex_index]; checked[neighbour_vertex_index] = true; workOnEdges(neighbour_vertex_index, components, checked); } } /* Find the components number and map the current components indexes to better ones (for example from 0, 2, 3, 6 - to 0,1,2,3). This method initializes m_components. The target of this action is to return also the components number (that is computed in the method) */ int[] mapToContinuous(int[] lowest_indexes) { // The result array int[] comp_indexes = new int[lowest_indexes.length]; // Initialization for(int i=0; i= cr_size) throw new Exception("OVGraph::getCR - Error in passing all array to result array"); else result[next++] = getIndex(i); } } return result; } /* Get the blocks number of each component in CR. Find for each component two different neighnbours (if it has) */ void fillComponentsBlocksNumbers(C_component[] components, int[] CR, int[] CR_components_indexes) throws Exception { if(CR.length == 0) throw new Exception("CR is empty"); // An arry for counting the blocks of each component in CR int value; int comp_index; int previous_index = CR_components_indexes[CR.length-1]; // last index // Scan CR for(int position=0; position merge <0,2> (1, 3, 4, 5, 6, 7, 8, 9)--> merge <1,4> (3, 5, 6, 7, 8 ,9)--> merge <3,6> (5, 7, 8, 9)--> merge <5,8> (7, 9)--> merge <7,9> () */ private void getHurdlesReversalsEven(boolean[] hurdilities, Reversal[] reversals_array, int from_index, int to_index) throws Exception { // These variables represents the indexes of the components that are hurdles int first = 0; int second, third; int start, end; int merges_num = to_index + 1 - from_index; if(merges_num == 0) // No hurdles return; int next_reversal_index = from_index; // Make all the merges for(int i=1; i<=merges_num; i++) { // Find the next first while(hurdilities[first] == false) first++; start = first; // Find the next second second = first + 1; while(hurdilities[second] == false) second++; if(i < merges_num) { // Not last iteration third = second + 1; // Find the next third while(hurdilities[third] == false) third++; end = third; } else end = second; mergeHurdles(start, end, reversals_array, next_reversal_index); next_reversal_index++; // Update the hurdles array hurdilities[start] = false; hurdilities[end] = false; } } // Add to the reversals array the reversal that merges hurdles with the given components id's private void mergeHurdles(int component1, int component2, Reversal[] reversals, int next_reversal) throws Exception { /* The endpoints group of a componnt must start with a even position and end with odd position (for example start with 0 and end in 7). Furthermore, the second position must be the first position + 1 since two endpoints with black edge stick together when dividing to components */ if(m_components == null) this.makeComponents(); // This one must be odd int start_reversal = getPosition(m_components[component1].m_vertices[1]); // This one must be even int end_reversal = getPosition(m_components[component2].m_vertices[0]); reversals[next_reversal] = new Reversal(start_reversal, end_reversal); } /* This method compute the reversals for clearing the hurdles. The result is inserted to the array in thre specified indexes */ private void getHurdlesReversalsOdd(boolean[] hurdilities, Reversal[] reversals_array, int from_index, int to_index) throws Exception { int simple_hurdle = findSimpleHurdle(hurdilities); if(simple_hurdle == -1) { clearFortress(hurdilities, reversals_array, from_index, to_index); return; } // The graph isn't a fortress // We get an edge endpoints as the reversal endpoints int start_position = getPosition(m_components[simple_hurdle].m_vertices[0]) + 1; int start_index = getIndex(start_position); int end_index = getNeighbourIndex(start_index); int end_position = getPosition(end_index); // Generate the first reversal reversals_array[from_index] = new Reversal(start_position, end_position); // Update the hurdles array that this hurdle is terminated hurdilities[simple_hurdle] = false; // Take care of the rest getHurdlesReversalsEven(hurdilities, reversals_array, from_index+1, to_index); } // Return the index of the first simple hurdle or -1 if it can't find one private int findSimpleHurdle(boolean[] hurdilities) throws Exception { if(m_components == null) makeComponents(); for(int i=0; i merge <0,2> (1, 3, 4, 5, 6, 7, 8, 9, 10)--> merge <1,4> (3, 5, 6, 7, 8 ,9, 10)--> merge <3,6> (5, 7, 8, 9, 10)--> merge <5,8> (7, 9, 10)--> merge <7,9> (79, 10)--> merge <79,10> () */ private void clearFortress(boolean[] hurdilities, Reversal[] reversals_array, int from_index, int to_index) throws Exception { int first = 0; int second, third, start, end; int merges_num = to_index + 1 - from_index; int next_reversal_index = from_index; // Make all the merges but the last one for(int i=1; i<=merges_num-1; i++) { // Find the start hurdle while(hurdilities[first] == false) first++; start = first; // Find the end hurdle second = first + 1; while(hurdilities[second] == false) second++; third = second + 1; // Find the next third while(hurdilities[third] == false) third++; end = third; mergeHurdles(start, end, reversals_array, next_reversal_index); next_reversal_index++; // Update the hurdles array hurdilities[start] = false; hurdilities[end] = false; } /* Done merges_num - 1 merges. We have now 2 hurdles to merge (79, 10 in the example). We can reach the merged new hurdle through index of one of its previous two hurdles (which are now in the start and end variables) and the second hurdle is the last one of the originals */ start = first; // Find the last true hurdle while(hurdilities[first] == false) first++; end = first; mergeHurdles(start, end, reversals_array, next_reversal_index); } /* ***************** HAPPY CLIQUE METHODS ***************** */ // One public method and some private auxilary methods /* Find a happy clique in the graph. Pseudo code for the algorithm for finding the clique : variables: 1. C is the clique 2. T is a vertex that contains 3. Ej is the biggest (by left endpoint and as a result of the cliqueness by right endpoint too) vertex of C 4. E1 is the smallest vertex of C Flow: 1. Make a list of the oriented vertices {e1, e2, e3, e4, ...} 2. Initialize C as {e1} and T as undefined 3. Pass on the list of oriented vertices and update C and T according to the following rules: foreach vertex Ei if R(Ej) < L(Ei) break // R(Ej) > L(Ei) if((T is defined) && (R(T) L(Ei) , R(Ei) > R(Ej) if(L(Ei) < R(E1)) // Case 2a T unchanged , C = union(C, {Ei}) continue else // Case 2b T unchanged, C = {Ei} 4. return C */ public List findHappyClique() throws Exception { int[] oriented_vertices = getOrientedVerticesByLeftOrder(); if(oriented_vertices.length == 0) return null; // Initialize E1 and Ej int first_in_happy_clique = oriented_vertices[0]; int last_in_happy_clique = first_in_happy_clique; // Initialize C as {e1} and T as undefined List happy_clique = new List(); // C happy_clique.add(first_in_happy_clique); int container_vertex_index = -1; // T (undefined) int left_ei, right_ej, right_ei; // Pass on the list of oriented vertices and update C and T for(int i=1; i L(Ei) if( (container_vertex_index != -1) && (getRightEndpoint(container_vertex_index) < right_ei)) // Case 1 continue; // else if(right_ei < right_ej) { // Case 2c (Ej contains Ei+1) happy_clique = new List(); happy_clique.add(oriented_vertices[i]); container_vertex_index = last_in_happy_clique; first_in_happy_clique = oriented_vertices[i]; last_in_happy_clique = oriented_vertices[i]; continue; } // R(Ej) > L(Ei) , R(Ei) > R(Ej) if(left_ei < getRightEndpoint(first_in_happy_clique)) { // Case 2a happy_clique.add(oriented_vertices[i]); last_in_happy_clique = oriented_vertices[i]; continue; } else { // Case 2b happy_clique = new List(); happy_clique.add(oriented_vertices[i]); first_in_happy_clique = oriented_vertices[i]; last_in_happy_clique = oriented_vertices[i]; continue; } } return happy_clique; } // TBD public int findVertexWithMaxUnorientedDegree(List happy_clique) throws Exception { // Hold the vertices in the clique ordered by endpoints int[] vertices = happy_clique.getElementsInArrayByInsertionOrder(); // Partition the real line to 2j+1 bins. [0] is the min and [1] - the max int bins_number = 2 * vertices.length + 1; int[][] bins = new int[bins_number][2]; bins[0][0] = -50000; // Fill the bins int left, right; for(int i=0; i 0) { sum_array[1]++; sum_array[m+1]--; } M = left_bin + right_bin - vertices.length - m; if(M < vertices.length) sum_array[M + 1]++; continue; } throw new Exception("OVGraph::findVertexWithMaxUnorientedDegree - unexpected error"); } // sum_array is now full int max_degree = -1; int max_index = -1; int sum = 0; for(int i=1; i max_degree) { max_degree = sum; max_index = i; } } return vertices[max_index-1]; // the -1 is for the difference in the indexing } // Get 2 arrays (that has he same values) and map one to the other // TBD - decide if it is more efficient to use quadratic algorithm on the permutation size private int[] map(int[] source, int[] target) throws Exception { if(target.length != source.length) throw new Exception("OVGraph::map - invoked with arrays with different sizes"); int[] result = new int[source.length]; int[] reverse_target = new int[this.getNumOfVertices()]; // Initialize the array for(int i=0; i=0; position--) { vertex_index = getVertexIndexByPosition(position); if(check_array[vertex_index]) // already found the right endpoint continue; // left endpoint // else check_array[vertex_index] = true; if(isUnoriented(vertex_index)) temp_result.add(vertex_index); // Check if we already found all the left endpoints (and we can quit) found_right++; if(found_right == vertices_num) break; } int[] result = temp_result.getElementsInArrayNotByInsertionOrder(); return result; } public boolean isLeftEndpoint(int index) throws Exception { int vertex_index = getVertexIndexByIndex(index); int left = getPosition(getLeftEndpoint(vertex_index)); return (index == left); } public void permutationChanged() throws Exception { this.m_components = null; this.makeComponents(); } public int[] getHurdlesIndexes() throws Exception { if(m_components == null) makeComponents(); List hurdlesList = new List(); for(int i=0; i