String Permutation Generator

Published 25 February 06 10:46 PM | adrian

From yesterday's .NET Internal Meeting (dIM): Generate a list of permutation of a string, optimize for speed and space. Here's the code:

Dim inputString As String = Console.ReadLine

For x As Long = 0 To Math2.Factorial(inputString.Length) - 1

  Dim outputstring As String() = New String(inputString.Length) {}

  Dim outputInteger As Integer() = _

    Math2.Permutation(inputString.Length, x)

 

  For y As Integer = 0 To outputInteger.Length - 1

    outputstring(y) = inputString(outputInteger(y))

    Console.Write(outputstring(y))

  Next

  Console.WriteLine()

Next x

I need to use two functions not available in System.Math, so I’ve extended to System.Math2, containing two functions; Factorial and Permutation. Factorial is a standard recursive multiplication, while Permutation uses a more advanced technique. I stumbled on this technique while doing a small simulation project (where a random permutation of 20 elements was needed). Got it from MSDN, the link? Go find it yourself…

Using Permutation function, I need to enter two arguments, the number of elements, and the permutation “ID” to return.

Finally, it is just a matter of conversion between integers and characters (the original Permutation function is designed for a series of integers, not characters).

You’ll need the Permutation function to run the code above. Drop me a comment if you need it (or unsuccessful looking for it on MSDN)!

Share this post: | | | |

Comments

# adrian said on February 26, 2006 03:14 AM:

Maksudnya bukan pakai API !!! pakai pure language feature ...

# adrian said on February 26, 2006 10:20 AM:

Lah ngga ada kali API System.Math2.Factorial sama Permutation. Itu gw mesti bikin sendiri. Cuma biar ngga ribet, hide it...

Anyway, it's just works... :D

# adrian said on February 26, 2006 03:23 PM:

Haha,

si Dondy bisa ngomong doang, ngeremehin SA. Padahal dia sendiri belum tentu bisa.

Ini soal basic kalo mau masuk Microsoft Redmond jadi SDE :) , and Godong, well, u seem to understand Computer Science well eventhough you're from Industrial Engineering field!

Congrats dude!

# adrian said on February 27, 2006 05:54 AM:

Ya di post dong :D System.Math2 lu whatever itu :D

Dondy

# adrian said on February 27, 2006 05:58 AM:

Compare with this
http://www.mredkj.com/vbnet/permutation.html

and here.. old classic vb :D

http://www.codeguru.com/vb/gen/vb_misc/algorithms/article.php/c5591/

should be generated faster on ; language :D

# adrian said on February 27, 2006 06:02 AM:

Akhirnya ada juga yang minta... :D

System.Math2.Permutation

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/permutations.asp

System.Math2.Factorial

Public Shared Function Factorial( _
ByVal i As Integer) As Int64
If i = 0 Then Return 1
If i = 1 Then Return i _
Else Return i * Factorial(i - 1)
End Function

# adrian said on February 27, 2006 06:08 AM:

gw pikir bikin sendiri... :( ternyata ngembat msdn...

# adrian said on February 27, 2006 06:14 AM:

Better than nothing... Experience gw kan kaga nyampe situ Don! :D

# adrian said on February 27, 2006 02:34 PM:

:)

As Dondy said, YOU write the API. Not using the API. That's the test is all about.

You'll writing API, not using API.

# adrian said on February 27, 2006 02:39 PM:

Btw, you use Long or even Int64 as the return value for factorial of a number? Nice & naive try. :)

He..he.. someone should really learn algorithm and the like.

Try to calculate 10000 factorial to your function! ;)

Anyway, nice attempt Godong. What about the other SA?

# adrian said on February 27, 2006 05:32 PM:

Norm: ini gw yang write, ntar gw bikin yang optimizednya lah... :D

Terus ada apa dengan Int64?

Ini maksimumnya cuma sampai dengan 20 fact.

# adrian said on February 27, 2006 06:32 PM:

Kenapa nggak coba pakai cached Factorial. Jadi hasil yang pernah di hitung sebelumnya di cached dan dipakai untuk perhitungan selanjutnya. Contoh sebelumnya kita pernah hitung Factorial(5). Lalu kita hitung Factorial(6), maka kita tinggal ambil dari cached hasil Factorial(5) dan kemudian dikalikan dengan angka 6, akhirnya sama dengan perhitungan Factorial(6). Ini perform faster overall, tapi memang tidak reduce memory, tapi reduce stack memory usage kalau pakai recursif.

Ini hanya salah satu teknik, masih banyak teknik lain untuk improve perhitungan-perhitungan model begini.

Just my .5 cents

# adrian said on March 6, 2006 09:38 AM:

blogs kalo hari sabtu minggu ga bisa diakses ya? gw dah coba neh tapi cupu abis, pake pendekatan naive recursion gitu, jadi pasti banyak keterbatasan dalam space dan performance. Not the efficient way to do it, but it works :p gw tau ga bakal bisa menuhin deadline loe jadi gw post di sini aja yah, sory kalo kepanjangan. lagian SDKnya kalo gw liat gw jadi bingung :( harus mengimplement sebuah fungsi generatePermutation() yang return typenya String[]?? kalo begitu bearti programnya cepet jebol donk kalo hasil permutationnya banyak :( jadi gw bikin benchmark sendiri dech berdasarkan file dll u heheh (sorry for "ILDASM"-ing ur dll Adrian :p)

I'm not too good in this kind of algorithm stuff, so this takes my whole saturday to code, then at night the blogs can't be accessed so I can't post it. What a pity of me :( I just visualize the problem as a completely connected unweighted graph, without any pruning or dynamic programming to eliminate the identical permutation. you can directly test the program and input your very,very long string and see the program explode. But the string "INDCRulez!" (length 10) will run ok :p

Adrian, would u please benchmark the code in your machine? :( (I'm just curious to see how it end up)

Norman : I've read your post bout the knuth series. I have one hardcopy (the 1st book about fundamental algorithm) at home, the one which I copied "illegally" from my campus' library in my 2nd year study LOL. I collapse on it after several sub chapters >_< Right now I'm not using it, if you want to borrow just plz let me know :p

-----begin of code------
namespace permute
{
public class MyPerm
{
StringBuilder s;
private static Int64 count;
string inputString;
char[] str;
short length;
bool [] visited; //the i-th node visited or not
short [] node_visited; //the node visited at i-th level

void InitVars()
{
visited = new bool[length];
node_visited = new short[length+1];
s = new StringBuilder(length + 1);
}

void ResetAll()
{
short i;
for (i = 0; i < length; i++)
{
visited[i] = false;
node_visited[i] = -1;
}
s.Remove(0, s.Length);
node_visited[i] = -1;
}

void dfs(short source, short dst, string currStr, short level, short pathIndex)
{
short x;
this.visited[pathIndex] = true;
this.node_visited[level] = pathIndex;
s.Append(str[pathIndex]);

if (level == length-1)
{
count++;
//uncomment the line below to see the result, but slower performance
//Console.WriteLine("#" +count + " " +currStr +str[pathIndex] +str[dst]);
this.node_visited[level] = -1;
this.visited[pathIndex] = false;
return;
}
else
{
for (x = 0; x < length; x++)
{
if (visited[x] == true || x == source || x == dst)
continue;
else
{
dfs(source, dst, s.ToString(), Convert.ToInt16(level + 1), x);

s.Remove(s.Length - 1, 1);
this.node_visited[level] = -1;
this.visited[x] = false;
}
}
}
}

public static void Main(string[] args)
{
short src, dest, x, len;
DateTime begin, end;
MyPerm p = new MyPerm();
Console.Write("Enter Input String : ");

p.inputString = Console.ReadLine();
p.str = p.inputString.ToCharArray();

len = p.length = Convert.ToInt16(p.inputString.Length);
if (len < 3)
{
Console.WriteLine("too small! :p");
}
else
{
p.InitVars();
Console.WriteLine("Start ! Processing...");

begin = DateTime.Now;
for (src = 0; src < len; src++)
{
for (dest = 0; dest < len; dest++)
{
if (src == dest)
continue;

for (x = 0; x < len; x++)
{
p.ResetAll();
p.visited[src] = true;
if (p.visited[x] == true || x == src || x == dest)
continue;

p.node_visited[1] = src;
p.s.Append(p.str[src]);

p.dfs(src, dest, p.s.ToString(), 2, x);
}
}
}
end = DateTime.Now;
Console.WriteLine("Start :" + begin);
Console.WriteLine("End : " + end);
TimeSpan execTime = end - begin;
double result = execTime.TotalMilliseconds;
Console.WriteLine(result);
}

Console.WriteLine("Finished");
Console.ReadKey();
}
}
}
------end of code--------