Converting a decimal to a mixed-radix (base) number - math

How do you convert a decimal number to mixed radix notation?
I guess that given an input of an array of each of the bases, and the decimal number, it should output an array of the values of each column.

Pseudocode:
bases = [24, 60, 60]
input = 86462 #One day, 1 minute, 2 seconds
output = []
for base in reverse(bases)
output.prepend(input mod base)
input = input div base #div is integer division (round down)

Number -> set:
factors = [52,7,24,60,60,1000]
value = 662321
for i in n-1..0
res[i] = value mod factors[i]
value = value div factors[i]
And the reverse:
If you have the number like 32(52), 5(7), 7(24), 45(60), 15(60), 500(1000) and you want this converted to decimal:
Take number n, multiply it with the factor of n-1, continue for n-1..n=0
values = [32,5,7,45,15,500]
factors = [52,7,24,60,60,1000]
res = 0;
for i in 0..n-1
res = res * factors[i] + values[i]
And you have the number.

In Java you could do
public static int[] Number2MixedRadix(int[] base, int number) throws Exception {
//NB if the max number you want # a position is say 3 then the base# tha position
//in your base array should be 4 not 3
int[] RadixFigures = new int[base.length];
int[] PositionPowers = new int[base.length];
PositionPowers[base.length-1] = 1;
for (int k = base.length-2,pow = 1; k >-1; k--){
pow*=base[k+1];
PositionPowers[k]=pow;
}for (int k = 0; k<base.length; k++){
RadixFigures[k]=number/PositionPowers[k];
if(RadixFigures[k]>base[k])throw new Exception("RadixFigure#["+k+"] => ("+RadixFigures[k]+") is > base#["+k+"] => ("+base[k]+") | ( number is Illegal )");
number=number%PositionPowers[k];
}return RadixFigures;
}
Example
//e.g. mixed-radix base for 1day
int[] base = new int[]{1, 24, 60, 60};//max-day,max-hours,max-minutes,max-seconds
int[] MixedRadix = Number2MixedRadix(base, 19263);//19263 seconds
//this would give [0,5,21,3] => as per 0days 5hrs 21mins 3secs
Reversal
public static int MixedRadix2Number(int[] RadixFigures,int[] base) throws Exception {
if(RadixFigures.length!=base.length)throw new Exception("RadixFigures.length must be = base.length");
int number=0;
int[] PositionPowers = new int[base.length];
PositionPowers[base.length-1] = 1;
for (int k = base.length-2,pow = 1; k >-1; k--){
pow*=base[k+1];
PositionPowers[k]=pow;
}for (int k = 0; k<base.length; k++){
number+=(RadixFigures[k]*PositionPowers[k]);
if(RadixFigures[k]>base[k])throw new Exception("RadixFigure#["+k+"] => ("+RadixFigures[k]+") is > base#["+k+"] => ("+base[k]+") | ( number is Illegal )");
}return number;
}

I came up with a slightly different, and probably not as good method as the other ones here, but I thought I'd share anyway:
var theNumber = 313732097;
// ms s m h d
var bases = [1000, 60, 60, 24, 365];
var placeValues = []; // initialise an array
var currPlaceValue = 1;
for (var i = 0, l = bases.length; i < l; ++i) {
placeValues.push(currPlaceValue);
currPlaceValue *= bases[i];
}
console.log(placeValues);
// this isn't relevant for this specific problem, but might
// be useful in related problems.
var maxNumber = currPlaceValue - 1;
var output = new Array(placeValues.length);
for (var v = placeValues.length - 1; v >= 0; --v) {
output[v] = Math.floor(theNumber / placeValues[v]);
theNumber %= placeValues[v];
}
console.log(output);
// [97, 52, 8, 15, 3] --> 3 days, 15 hours, 8 minutes, 52 seconds, 97 milliseconds

I tried a few of the examples before and found an edge case they didn't cover, if you max out your scale you need to prepend the result from the last step
def intToMix(number,radix=[10]):
mixNum=[]
radix.reverse()
for i in range(0,len(radix)):
mixNum.append(number%radix[i])
number//=radix[i]
mixNum.append(number)
mixNum.reverse()
radix.reverse()
return mixNum
num=60*60*24*7
radix=[7,24,60,60]
tmp1=intToMix(num,radix)

Related

How to find two optimal weights in a vector?

Imagine you're given an unsorted array [5,11,7,4,19,8,11,6,17] and a max weight 23. [similar to Two Sum Problem by a bit different]
One needs to find two optimal weights (by which I mean if two weights that are (almost or not) half of the weight you're trying to find) in this case [5,17], [3,19], [11,11] so I need to return [11,11].
I was taken back by the problem, and could not solve it. [I was not allowed to use structs]
I tried to sort [3, 5, 6, 7, 8, 11, 11, 17, 19] and search from both ends and store indexes of values that were <= max weight in a vector as a pair (like v[i], v[i+1] and check them later by their pairs) then return a pair with both largest vals, but got confused.
[although, weights were doubles and I did not see duplicates at that set I did not use unsorted_map(hashMap), might it've worked?]
Can anyone suggest how should I go about this problem? is it similar to "knapsack problem"? Thank you
You can use Two Pointer Approach for the problem.
Algorithm:
Sort the array.
Have two pointers startIndex and endIndex to 0 and arraySize-1.
sum = arr[startIndex] + arr[endIndex]
If sum is less than or equal to 23, increment startIndex else decrement endIndex.
keep track of closest value using a variable.
finish when startIndex == endIndex
Code in Java:
public class Solution {
private ArrayList<Integer> twoSumClosest(ArrayList<Integer> a, int s) {
// Sort the arraylist
Collections.sort(a);
// closests sum we got till now
int sumClosest = Integer.MIN_VALUE;
// indexes used to traverse
int startIndex = 0;
int endIndex = a.size() - 1 ;
// answer Indexes
int firstIndex = 1;
int secondIndex = a.size() - 1;
while( startIndex < endIndex ) {
if( a.get(startIndex) + a.get(endIndex) > s) {
endIndex--;
continue;
} else {
if( a.get(startIndex) + a.get(endIndex) > sumClosest ) {
sumClosest = a.get(startIndex) + a.get(endIndex);
firstIndex = startIndex;
secondIndex = endIndex;
}
startIndex++;
}
}
ArrayList<Integer> ans = new ArrayList<>();
ans.add(firstIndex);
ans.add(secondIndex);
return ans;
}
}
Time Complexity: O(nlogn)
O(n) if array was already sorted
Extra Space Needed: O(1)

Challenge with vector: how to split a vector based on max/min conditions

I've recently come across the following problem:
Let say I have an vector of random length (L) of 0 and 1 randomly distributed (for example [0,1,1,1,0,0,1,0]), I need to split the vector in two sub-vector at index K so following conditions are valid:
the left sub-vector must contains the maximum number of elements from
K in reverse order such as the number of zeros must be greater or
equal to the number of 1s
the right sub vector must contains the maximum number of element starting from K+1 such as the number of 1s must be greater or equal to the number of zeros
For example, [1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0] the split is at index 9, left vector is [1,0], right vector [0,1]
I wrote the following solution but the complexity is O(L^2). I think there could be a solution with complexity of worst case O(L) but I cannot find anything that can help me. Any idea? Thanks
var max = 0;
var kMax = -1;
var firstZeroFound = false;
for (var i = 0; i < testVector.Length - 1; i++)
{
if (!firstZeroFound)
{
if (testVector[i]) continue;
firstZeroFound = true;
}
var maxZero = FindMax(testVector, i, -1, -1, false);
if (maxZero == 0) continue;
var maxOne = FindMax(testVector, i + 1, testVector.Length, 1, true);
if (maxOne == 0) continue;
if ((maxZero + maxOne) <= max)
continue;
max = maxOne + maxZero;
kMax = i;
if (max == testVector.Length)
break;
}
Console.Write("The result is {0}", kMax);
int FindMax(bool[] v, int start, int end, int increment, bool maximize)
{
var max = 0;
var sum = 0;
var count = 0;
var i = start;
while (i != end)
{
count++;
if (v[i])
sum++;
if (maximize)
{
if (sum * 2 >= count)
max = count;
}
else if (sum * 2 <= count)
{
max = count;
}
i += increment;
}
return max;
}
I think you should look at rle.
y <- c(1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0)
z <- rle(y)
d <- cbind(z$values, z$lengths)
[,1] [,2]
[1,] 1 9
[2,] 0 1
[3,] 1 1
[4,] 0 8
Basically, rle calculates the lengths of 0's and 1's at each level.
From here things may go easier for you.

Encrypt the message NEED HELP by translating the letters into numbers..answer is UTTQ CTOA...how?

Encrypt the message NEED HELP by translating the letters into numbers, applying the
encryption function f (p) = (3p + 7) mod 26, and then translating the numbers back into
letters.
Ans: Encrypted form: UTTQ CTOA.
could someone please explain to me how they got this answer
first you have to assign a number to each letter:
A = 0; B = 1; C = 2 ....
then you apply the function to the numbers you get and convert it back to letters:
N would be 13, so 13 * 3 = 39, + 7 = 46
then mod 26 = 20
converting back, 20 = U
If you do it on all the letters of your sentence you'll have the encrypted form
and here the C# code to do this:
private static string encrypt(string s)
{
char[] tmp = new char[s.Length];
int i = 0;
foreach (char c in s)
{
tmp[i] = (char)((((c - 'A') * 3 + 7) % 26) + 'A');
i++;
}
return new string(tmp);
}
and here your decrypt function (ok this one is messy but works):
private static string decrypt(string s)
{
string res = s;
for (int i = 0; i < 5; i++)
res = encrypt(res);
return res;
}

Finding all cycles in undirected graphs

I need a working algorithm for finding all simple cycles in an undirected graph. I know the cost can be exponential and the problem is NP-complete, but I am going to use it in a small graph (up to 20-30 vertices) and the cycles are small in number.
After a long research (mainly here) I still don't have a working approach. Here is a summary of my search:
Finding all cycles in an undirected graph
Cycles in an Undirected Graph -> detects only whether there is a cycle or not
Finding polygons within an undirected Graph -> very nice description, but no solution
Finding all cycles in a directed graph -> finds cycles only in directed graphs
Detect cycles in undirected graph using boost graph library
The only answer I found, which approaches my problem, is this one:
Find all cycles in graph, redux
It seems that finding a basic set of cycles and XOR-ing them could do the trick. Finding a basic set of cycles is easy, but I don't understand how to combine them in order to obtain all cycles in the graph...
For an undirected graph the standard approach is to look for a so called cycle base : a set of simple cycles from which one can generate through combinations all other cycles. These are not necessarily all simple cycles in the graph. Consider for example the following graph:
A
/ \
B ----- C
\ /
D
There are 3 simple cycles here : A-B-C-A, B-C-D-B and A-B-D-C-A. You can however take each 2 of these as a basis and obtain the 3rd as a combination of the 2. This is a substantial difference from directed graphs where one can not combine so freely cycles due to the need to observe edge direction.
The standard baseline algorithm for finding a cycle base for an undirected graph is this : Build a spanning tree and then for each edge which is not part of the tree build a cycle from that edge and some edges on the tree. Such cycle must exist because otherwise the edge would be part of the tree.
For example one of the possible spanning trees for the sample graph above is this:
A
/ \
B C
\
D
The 2 edges not in the tree are B-C and C-D. And the corresponding simple cycles are A-B-C-A and A-B-D-C-A.
You can also build the following spanning tree:
A
/
B ----- C
\
D
And for this spanning tree the simple cycles would be A-B-C-A and B-C-D-B.
The baseline algorithm can be refined in different ways. To the best of my knowledge the best refinement belongs to Paton (K. Paton, An algorithm for finding a fundamental set of cycles for an undirected linear graph, Comm. ACM 12 (1969), pp. 514-518.). An open source implementation in Java is available here : http://code.google.com/p/niographs/ .
I should have mentioned how you combine simple cycles from the cycle base to form new simple cycles. You start off by listing in any (but fixed hereafter) order all edges of the graph. Then you represent cycles by sequences of zeros and ones by placing ones in the positions of edges which belong to the cycle and zeros in the positions of edges which are not part of the cycle. Then you do bitwise exclusive OR (XOR) of the sequences. The reason you do XOR is that you want to exclude edges which belong to both cycles and thus make the combined cycle non-simple. You need to check also that the 2 cycles have SOME common edges by checking that the bitwise AND of the sequences is not all zeros. Otherwise the result of XOR will be 2 disjoint cycles rather than a new simple cycle.
Here is an example for the sample graph above:
We start by listing the edges : ((AB), (AC), (BC), (BD), (CD)). Then the simple cycles A-B-C-A, B-D-C-B and A-B-D-C-A are represented as (1, 1, 1, 0, 0), (0, 0, 1, 1, 1) and (1, 1, 0, 1, 1). Now we can for example XOR A-B-C-A with B-D-C-B and the result is (1, 1, 0, 1, 1) which is exactly A-B-D-C-A. Or we can XOR A-B-C-A and A-B-D-C-A with the result being (0, 0, 1, 1, 1). Which is exactly B-D-C-B.
Given a cycle base you can discover all simple cycles by examining all possible combinations of 2 or more distinct base cycles. The procedure is described in more detail here : http://dspace.mit.edu/bitstream/handle/1721.1/68106/FTL_R_1982_07.pdf on page 14.
For the sake of completeness, I would notice that it seems possible (and inefficient) to use algorithms for finding all simple cycles of a directed graph. Every edge of the undirected graph can be replaced by 2 directed edges going in opposite directions. Then algorithms for directed graphs should work. There will be 1 "false" 2-node cycle for every edge of the undirected graph which will have to be ignored and there will be a clockwise and a counterclockwise version of every simple cycle of the undirected graph. Open source implementation in Java of algorithms for finding all cycles in a directed graph can be found at the link I already quoted.
Axel, I've translated your code to python. About 1/4th the lines of code and clearer to read.
graph = [[1, 2], [1, 3], [1, 4], [2, 3], [3, 4], [2, 6], [4, 6], [8, 7], [8, 9], [9, 7]]
cycles = []
def main():
global graph
global cycles
for edge in graph:
for node in edge:
findNewCycles([node])
for cy in cycles:
path = [str(node) for node in cy]
s = ",".join(path)
print(s)
def findNewCycles(path):
start_node = path[0]
next_node= None
sub = []
#visit each edge and each node of each edge
for edge in graph:
node1, node2 = edge
if start_node in edge:
if node1 == start_node:
next_node = node2
else:
next_node = node1
if not visited(next_node, path):
# neighbor node not on path yet
sub = [next_node]
sub.extend(path)
# explore extended path
findNewCycles(sub);
elif len(path) > 2 and next_node == path[-1]:
# cycle found
p = rotate_to_smallest(path);
inv = invert(p)
if isNew(p) and isNew(inv):
cycles.append(p)
def invert(path):
return rotate_to_smallest(path[::-1])
# rotate cycle path such that it begins with the smallest node
def rotate_to_smallest(path):
n = path.index(min(path))
return path[n:]+path[:n]
def isNew(path):
return not path in cycles
def visited(node, path):
return node in path
main()
The following is a demo implementation in C# (and Java, see end of answer) based on depth first search.
An outer loop scans all nodes of the graph and starts a search from every node. Node neighbours (according to the list of edges) are added to the cycle path. Recursion ends if no more non-visited neighbours can be added. A new cycle is found if the path is longer than two nodes and the next neighbour is the start of the path. To avoid duplicate cycles, the cycles are normalized by rotating the smallest node to the start. Cycles in inverted ordering are also taken into account.
This is just a naive implementation.
The classical paper is: Donald B. Johnson. Finding all the elementary circuits of a directed graph. SIAM J. Comput., 4(1):77–84, 1975.
A recent survey of modern algorithms can be found here
using System;
using System.Collections.Generic;
namespace akCyclesInUndirectedGraphs
{
class Program
{
// Graph modelled as list of edges
static int[,] graph =
{
{1, 2}, {1, 3}, {1, 4}, {2, 3},
{3, 4}, {2, 6}, {4, 6}, {7, 8},
{8, 9}, {9, 7}
};
static List<int[]> cycles = new List<int[]>();
static void Main(string[] args)
{
for (int i = 0; i < graph.GetLength(0); i++)
for (int j = 0; j < graph.GetLength(1); j++)
{
findNewCycles(new int[] {graph[i, j]});
}
foreach (int[] cy in cycles)
{
string s = "" + cy[0];
for (int i = 1; i < cy.Length; i++)
s += "," + cy[i];
Console.WriteLine(s);
}
}
static void findNewCycles(int[] path)
{
int n = path[0];
int x;
int[] sub = new int[path.Length + 1];
for (int i = 0; i < graph.GetLength(0); i++)
for (int y = 0; y <= 1; y++)
if (graph[i, y] == n)
// edge referes to our current node
{
x = graph[i, (y + 1) % 2];
if (!visited(x, path))
// neighbor node not on path yet
{
sub[0] = x;
Array.Copy(path, 0, sub, 1, path.Length);
// explore extended path
findNewCycles(sub);
}
else if ((path.Length > 2) && (x == path[path.Length - 1]))
// cycle found
{
int[] p = normalize(path);
int[] inv = invert(p);
if (isNew(p) && isNew(inv))
cycles.Add(p);
}
}
}
static bool equals(int[] a, int[] b)
{
bool ret = (a[0] == b[0]) && (a.Length == b.Length);
for (int i = 1; ret && (i < a.Length); i++)
if (a[i] != b[i])
{
ret = false;
}
return ret;
}
static int[] invert(int[] path)
{
int[] p = new int[path.Length];
for (int i = 0; i < path.Length; i++)
p[i] = path[path.Length - 1 - i];
return normalize(p);
}
// rotate cycle path such that it begins with the smallest node
static int[] normalize(int[] path)
{
int[] p = new int[path.Length];
int x = smallest(path);
int n;
Array.Copy(path, 0, p, 0, path.Length);
while (p[0] != x)
{
n = p[0];
Array.Copy(p, 1, p, 0, p.Length - 1);
p[p.Length - 1] = n;
}
return p;
}
static bool isNew(int[] path)
{
bool ret = true;
foreach(int[] p in cycles)
if (equals(p, path))
{
ret = false;
break;
}
return ret;
}
static int smallest(int[] path)
{
int min = path[0];
foreach (int p in path)
if (p < min)
min = p;
return min;
}
static bool visited(int n, int[] path)
{
bool ret = false;
foreach (int p in path)
if (p == n)
{
ret = true;
break;
}
return ret;
}
}
}
The cycles for the demo graph:
1,3,2
1,4,3,2
1,4,6,2
1,3,4,6,2
1,4,6,2,3
1,4,3
2,6,4,3
7,9,8
The algorithm coded in Java:
import java.util.ArrayList;
import java.util.List;
public class GraphCycleFinder {
// Graph modeled as list of edges
static int[][] graph =
{
{1, 2}, {1, 3}, {1, 4}, {2, 3},
{3, 4}, {2, 6}, {4, 6}, {7, 8},
{8, 9}, {9, 7}
};
static List<int[]> cycles = new ArrayList<int[]>();
/**
* #param args
*/
public static void main(String[] args) {
for (int i = 0; i < graph.length; i++)
for (int j = 0; j < graph[i].length; j++)
{
findNewCycles(new int[] {graph[i][j]});
}
for (int[] cy : cycles)
{
String s = "" + cy[0];
for (int i = 1; i < cy.length; i++)
{
s += "," + cy[i];
}
o(s);
}
}
static void findNewCycles(int[] path)
{
int n = path[0];
int x;
int[] sub = new int[path.length + 1];
for (int i = 0; i < graph.length; i++)
for (int y = 0; y <= 1; y++)
if (graph[i][y] == n)
// edge refers to our current node
{
x = graph[i][(y + 1) % 2];
if (!visited(x, path))
// neighbor node not on path yet
{
sub[0] = x;
System.arraycopy(path, 0, sub, 1, path.length);
// explore extended path
findNewCycles(sub);
}
else if ((path.length > 2) && (x == path[path.length - 1]))
// cycle found
{
int[] p = normalize(path);
int[] inv = invert(p);
if (isNew(p) && isNew(inv))
{
cycles.add(p);
}
}
}
}
// check of both arrays have same lengths and contents
static Boolean equals(int[] a, int[] b)
{
Boolean ret = (a[0] == b[0]) && (a.length == b.length);
for (int i = 1; ret && (i < a.length); i++)
{
if (a[i] != b[i])
{
ret = false;
}
}
return ret;
}
// create a path array with reversed order
static int[] invert(int[] path)
{
int[] p = new int[path.length];
for (int i = 0; i < path.length; i++)
{
p[i] = path[path.length - 1 - i];
}
return normalize(p);
}
// rotate cycle path such that it begins with the smallest node
static int[] normalize(int[] path)
{
int[] p = new int[path.length];
int x = smallest(path);
int n;
System.arraycopy(path, 0, p, 0, path.length);
while (p[0] != x)
{
n = p[0];
System.arraycopy(p, 1, p, 0, p.length - 1);
p[p.length - 1] = n;
}
return p;
}
// compare path against known cycles
// return true, iff path is not a known cycle
static Boolean isNew(int[] path)
{
Boolean ret = true;
for(int[] p : cycles)
{
if (equals(p, path))
{
ret = false;
break;
}
}
return ret;
}
static void o(String s)
{
System.out.println(s);
}
// return the int of the array which is the smallest
static int smallest(int[] path)
{
int min = path[0];
for (int p : path)
{
if (p < min)
{
min = p;
}
}
return min;
}
// check if vertex n is contained in path
static Boolean visited(int n, int[] path)
{
Boolean ret = false;
for (int p : path)
{
if (p == n)
{
ret = true;
break;
}
}
return ret;
}
}
Here's just a very lame MATLAB version of this algorithm adapted from the python code above, for anyone who might need it as well.
function cycleList = searchCycles(edgeMap)
tic
global graph cycles numCycles;
graph = edgeMap;
numCycles = 0;
cycles = {};
for i = 1:size(graph,1)
for j = 1:2
findNewCycles(graph(i,j))
end
end
% print out all found cycles
for i = 1:size(cycles,2)
cycles{i}
end
% return the result
cycleList = cycles;
toc
function findNewCycles(path)
global graph cycles numCycles;
startNode = path(1);
nextNode = nan;
sub = [];
% visit each edge and each node of each edge
for i = 1:size(graph,1)
node1 = graph(i,1);
node2 = graph(i,2);
if node1 == startNode
nextNode = node2;
elseif node2 == startNode
nextNode = node1;
end
if ~(visited(nextNode, path))
% neighbor node not on path yet
sub = nextNode;
sub = [sub path];
% explore extended path
findNewCycles(sub);
elseif size(path,2) > 2 && nextNode == path(end)
% cycle found
p = rotate_to_smallest(path);
inv = invert(p);
if isNew(p) && isNew(inv)
numCycles = numCycles + 1;
cycles{numCycles} = p;
end
end
end
function inv = invert(path)
inv = rotate_to_smallest(path(end:-1:1));
% rotate cycle path such that it begins with the smallest node
function new_path = rotate_to_smallest(path)
[~,n] = min(path);
new_path = [path(n:end), path(1:n-1)];
function result = isNew(path)
global cycles
result = 1;
for i = 1:size(cycles,2)
if size(path,2) == size(cycles{i},2) && all(path == cycles{i})
result = 0;
break;
end
end
function result = visited(node,path)
result = 0;
if isnan(node) && any(isnan(path))
result = 1;
return
end
for i = 1:size(path,2)
if node == path(i)
result = 1;
break
end
end
Here is a C++ version of the python code above:
std::vector< std::vector<vertex_t> > Graph::findAllCycles()
{
std::vector< std::vector<vertex_t> > cycles;
std::function<void(std::vector<vertex_t>)> findNewCycles = [&]( std::vector<vertex_t> sub_path )
{
auto visisted = []( vertex_t v, const std::vector<vertex_t> & path ){
return std::find(path.begin(),path.end(),v) != path.end();
};
auto rotate_to_smallest = []( std::vector<vertex_t> path ){
std::rotate(path.begin(), std::min_element(path.begin(), path.end()), path.end());
return path;
};
auto invert = [&]( std::vector<vertex_t> path ){
std::reverse(path.begin(),path.end());
return rotate_to_smallest(path);
};
auto isNew = [&cycles]( const std::vector<vertex_t> & path ){
return std::find(cycles.begin(), cycles.end(), path) == cycles.end();
};
vertex_t start_node = sub_path[0];
vertex_t next_node;
// visit each edge and each node of each edge
for(auto edge : edges)
{
if( edge.has(start_node) )
{
vertex_t node1 = edge.v1, node2 = edge.v2;
if(node1 == start_node)
next_node = node2;
else
next_node = node1;
if( !visisted(next_node, sub_path) )
{
// neighbor node not on path yet
std::vector<vertex_t> sub;
sub.push_back(next_node);
sub.insert(sub.end(), sub_path.begin(), sub_path.end());
findNewCycles( sub );
}
else if( sub_path.size() > 2 && next_node == sub_path.back() )
{
// cycle found
auto p = rotate_to_smallest(sub_path);
auto inv = invert(p);
if( isNew(p) && isNew(inv) )
cycles.push_back( p );
}
}
}
};
for(auto edge : edges)
{
findNewCycles( std::vector<vertex_t>(1,edge.v1) );
findNewCycles( std::vector<vertex_t>(1,edge.v2) );
}
}
Inspired by #LetterRip and #Axel Kemper
Here is a shorter version of Java:
public static int[][] graph =
{
{1, 2}, {2, 3}, {3, 4}, {2, 4},
{3, 5}
};
public static Set<List<Integer>> cycles = new HashSet<>();
static void findNewCycles(ArrayList<Integer> path) {
int start = path.get(0);
int next = -1;
for (int[] edge : graph) {
if (start == edge[0] || start == edge[1]) {
next = (start == edge[0]) ? edge[1] : edge[0];
if (!path.contains(next)) {
ArrayList<Integer> newPath = new ArrayList<>();
newPath.add(next);
newPath.addAll((path));
findNewCycles(newPath);
} else if (path.size() > 2 && next == path.get(path.size() - 1)) {
List<Integer> normalized = new ArrayList<>(path);
Collections.sort(normalized);
cycles.add(normalized);
}
}
}
}
public static void detectCycle() {
for (int i = 0; i < graph.length; i++)
for (int j = 0; j < graph[i].length; j++) {
ArrayList<Integer> path = new ArrayList<>();
path.add(graph[i][j]);
findNewCycles(path);
}
for (List<Integer> c : cycles) {
System.out.println(c);
}
}
Here is a node version of the python code.
const graph = [[1, 2], [1, 3], [1, 4], [2, 3], [3, 4], [2, 6], [4, 6], [8, 7], [8, 9], [9, 7]]
let cycles = []
function main() {
for (const edge of graph) {
for (const node of edge) {
findNewCycles([node])
}
}
for (cy of cycles) {
console.log(cy.join(','))
}
}
function findNewCycles(path) {
const start_node = path[0]
let next_node = null
let sub = []
// visit each edge and each node of each edge
for (const edge of graph) {
const [node1, node2] = edge
if (edge.includes(start_node)) {
next_node = node1 === start_node ? node2 : node1
}
if (notVisited(next_node, path)) {
// eighbor node not on path yet
sub = [next_node].concat(path)
// explore extended path
findNewCycles(sub)
} else if (path.length > 2 && next_node === path[path.length - 1]) {
// cycle found
const p = rotateToSmallest(path)
const inv = invert(p)
if (isNew(p) && isNew(inv)) {
cycles.push(p)
}
}
}
}
function invert(path) {
return rotateToSmallest([...path].reverse())
}
// rotate cycle path such that it begins with the smallest node
function rotateToSmallest(path) {
const n = path.indexOf(Math.min(...path))
return path.slice(n).concat(path.slice(0, n))
}
function isNew(path) {
const p = JSON.stringify(path)
for (const cycle of cycles) {
if (p === JSON.stringify(cycle)) {
return false
}
}
return true
}
function notVisited(node, path) {
const n = JSON.stringify(node)
for (const p of path) {
if (n === JSON.stringify(p)) {
return false
}
}
return true
}
main()
Here is a vb .net version of the python code above:
Module Module1
' Graph modelled as list of edges
Public graph As Integer(,) = {{{1, 2}, {1, 3}, {1, 4}, {2, 3},
{3, 4}, {2, 6}, {4, 6}, {7, 8},
{8, 9}, {9, 7}}
Public cycles As New List(Of Integer())()
Sub Main()
For i As Integer = 0 To graph.GetLength(0) - 1
For j As Integer = 0 To graph.GetLength(1) - 1
findNewCycles(New Integer() {graph(i, j)})
Next
Next
For Each cy As Integer() In cycles
Dim s As String
s = cy(0)
For i As Integer = 1 To cy.Length - 1
s = s & "," & cy(i)
Next
Console.WriteLine(s)
Debug.Print(s)
Next
End Sub
Private Sub findNewCycles(path As Integer())
Dim n As Integer = path(0)
Dim x As Integer
Dim [sub] As Integer() = New Integer(path.Length) {}
For i As Integer = 0 To graph.GetLength(0) - 1
For y As Integer = 0 To 1
If graph(i, y) = n Then
' edge referes to our current node
x = graph(i, (y + 1) Mod 2)
If Not visited(x, path) Then
' neighbor node not on path yet
[sub](0) = x
Array.Copy(path, 0, [sub], 1, path.Length)
' explore extended path
findNewCycles([sub])
ElseIf (path.Length > 2) AndAlso (x = path(path.Length - 1)) Then
' cycle found
Dim p As Integer() = normalize(path)
Dim inv As Integer() = invert(p)
If isNew(p) AndAlso isNew(inv) Then
cycles.Add(p)
End If
End If
End If
Next
Next
End Sub
Private Function equals(a As Integer(), b As Integer()) As Boolean
Dim ret As Boolean = (a(0) = b(0)) AndAlso (a.Length = b.Length)
Dim i As Integer = 1
While ret AndAlso (i < a.Length)
If a(i) <> b(i) Then
ret = False
End If
i += 1
End While
Return ret
End Function
Private Function invert(path As Integer()) As Integer()
Dim p As Integer() = New Integer(path.Length - 1) {}
For i As Integer = 0 To path.Length - 1
p(i) = path(path.Length - 1 - i)
Next
Return normalize(p)
End Function
' rotate cycle path such that it begins with the smallest node
Private Function normalize(path As Integer()) As Integer()
Dim p As Integer() = New Integer(path.Length - 1) {}
Dim x As Integer = smallest(path)
Dim n As Integer
Array.Copy(path, 0, p, 0, path.Length)
While p(0) <> x
n = p(0)
Array.Copy(p, 1, p, 0, p.Length - 1)
p(p.Length - 1) = n
End While
Return p
End Function
Private Function isNew(path As Integer()) As Boolean
Dim ret As Boolean = True
For Each p As Integer() In cycles
If equals(p, path) Then
ret = False
Exit For
End If
Next
Return ret
End Function
Private Function smallest(path As Integer()) As Integer
Dim min As Integer = path(0)
For Each p As Integer In path
If p < min Then
min = p
End If
Next
Return min
End Function
Private Function visited(n As Integer, path As Integer()) As Boolean
Dim ret As Boolean = False
For Each p As Integer In path
If p = n Then
ret = True
Exit For
End If
Next
Return ret
End Function
End Module
It seems that the cycle finder above has some problems. The C# version fails to find some cycles. My graph is:
{2,8},{4,8},{5,8},{1,9},{3,9},{4,9},{5,9},{6,9},{1,10},
{4,10},{5,10},{6,10},{7,10},{1,11},{4,11},{6,11},{7,11},
{1,12},{2,12},{3,12},{5,12},{6,12},{2,13},{3,13},{4,13},
{6,13},{7,13},{2,14},{5,14},{7,14}
For example, the cycle: 1-9-3-12-5-10 is not found.
I tried the C++ version as well, it returns very large (tens of millions) number of cycles which is apparently wrong. Probably, it fails to match the cycles.
Sorry, I am in a bit of crunch and I have not investigated further. I wrote my own version based on post of Nikolay Ognyanov (thank you very much for your post). For the graph above my version returns 8833 cycles and I am trying to verify that it is correct. The C# version returns 8397 cycles.
This is NOT an answer!
#Nikolay Ognyano
1. Trying to understand how we should generate the combined cycles with simple cycles
I am trying to understand what you mentioned
You need to check also that the 2 cycles have SOME common edges by checking that the bitwise AND of the sequences is not all zeros. Otherwise the result of XOR will be 2 disjoint cycles rather than a new simple cycle.
I'd like to understand how we should deal with a graph like below:
0-----2-----4
| /| /
| / | /
| / | /
| / | /
|/ |/
1-----3
Assuming the fundamental/simple cycles are:
0 1 2
1 2 3
2 3 4
Apparently, if I use the following bitwise XOR and AND, it will miss the cycle 0 1 3 4 2.
bitset<MAX> ComputeCombinedCycleBits(const vector<bitset<MAX>>& bsets) {
bitset<MAX> bsCombo, bsCommonEdgeCheck; bsCommonEdgeCheck.set();
for (const auto& bs : bsets)
bsCombo ^= bs, bsCommonEdgeCheck &= bs;
if (bsCommonEdgeCheck.none()) bsCombo.reset();
return bsCombo;
}
I think the main issue is here bsCommonEdgeCheck &= bs? What should we use if there are more than 3 simple cycle to compose the combined cycle?
2. Trying to understand how we get the order of the combined cycle
For example, with the following graph:
0-----1
|\ /|
| \ / |
| X |
| / \ |
|/ \|
3-----2
Assuming the fundamental/simple cycles are:
0 1 2
0 2 3
0 1 3
After we use the bitwise XOR, we have completely lost the order of the simple cycles, and how can get the node order of the combined cycle?
The Matlab version missed something, function findNewCycles(path) should be:
function findNewCycles(path)
global graph cycles numCycles;
startNode = path(1);
nextNode = nan;
sub = [];
% visit each edge and each node of each edge
for i = 1:size(graph,1)
node1 = graph(i,1);
node2 = graph(i,2);
if (node1 == startNode) || (node2==startNode) %% this if is required
if node1 == startNode
nextNode = node2;
elseif node2 == startNode
nextNode = node1;
end
if ~(visited(nextNode, path))
% neighbor node not on path yet
sub = nextNode;
sub = [sub path];
% explore extended path
findNewCycles(sub);
elseif size(path,2) > 2 && nextNode == path(end)
% cycle found
p = rotate_to_smallest(path);
inv = invert(p);
if isNew(p) && isNew(inv)
numCycles = numCycles + 1;
cycles{numCycles} = p;
end
end
end
end

Most efficient way to concat Vectors

What is the most efficient way to insert one Vector into another at specific position?
For example:
var aa:Vector.<int> = Vector.<int>([1, 2, 3]);
var bb:Vector.<int> = Vector.<int>([9, 8, 7]);
This doesn't seems to work:
bb.splice(1, 0, aa);
The result is [9, 0, 8, 7].
For the moment there is no builtin function other than doing a loop over the Vector, here two methods (i have not timed them).
If bb can be a new Vector you can do for example:
var insertIndex:int = 1;
bb=bb.slice(0, insertIndex).concat(aa).concat(bb.slice(insertIndex));
If bb cannot be change you can do a splice but with preparing the elements to insert into a new Array:
var insertIndex:int = 1;
var parms:Array=[insertIndex, 0]; // prepare the arguments for the splice call
var j:int = 2; // length of the parms array
var len:int = aa.length;
for (var i:int = 0; i < len; i++, j++){
parms[j] = aa[i];
}
// call the splice with the new arguments
bb.splice.apply(bb, parms);
If you need to concat one after the other, as PatrickS mentionned bb.concat will do the job.
If you need to insert values in the middle you'll need something like
for each (var i : int in aa.reverse())
{
bb.splice(1,0,i);
}
or, more elegantly, this, if you cannot change aa
var insertingIndex : int = 2;
for each ( var i : int in aa )
{
bb.splice( insertingIndex, 0, i );
insertingIndex++;
}

Resources