That’s the algorithm I’ve tried to use
Anyway, just tried swapping the values using XOR swapping but it’s slower that maxscript swap, anyway, here’s the code:
(
print "V9"
gc()
mem = heapfree
start = timestamp()
seed(timestamp())
asize = 1000000
results = for i = 1 to asize collect i
for i = 1 to asize do
(
idx = random i asize
v1 = results[i]
v2 = results[idx]
v1 = bit.xor v1 v2
v2 = bit.xor v1 v2
v1 = bit.xor v1 v2
results[i] = v1
results[idx] = v2
)
end = timestamp()
format "processing: % seconds heap: %
" ((end - start) / 1000.0) (mem-heapfree)
format "Num unique elem %
" (results as bitarray).numberset
)
Results:
"V9"
processing: 3.651 seconds heap: 416065400L
Num unique elem 1000000
OK
for your knowledge…
all bit structure operations called directly from the structure causes big memory leaking.
put the function to a variable and call from there, and you will see the difference:
(
gc()
m1 = heapfree
for k=1 to 100000 do bit.xor 1 2
format "memory:%
" (m1 - heapfree)
)
(
gc()
m1 = heapfree
xor = bit.xor
for k=1 to 100000 do xor 1 2
format "memory:%
" (m1 - heapfree)
)
it works for any structure and any function from the structure.
Gotcha, thanks Denis. BTW any ideia why this is way slower than the max swap function ?
I checked the values for a 1000 element array and the shuffling seemed pretty good. Here is the code:
public class RandomNumberGenerator
{
public static int [ ] CreateRandomInts ( int count )
{
//Stopwatch sw = new Stopwatch ( );
//sw.Start ( );
int [ ] arr = new int [ count ];
for ( int i = 0; i < count; ++i )
arr [ i ] = i;
var arr2 = Shuffle ( arr );
//sw.Stop ( );
//Console.WriteLine ( sw.ElapsedMilliseconds / 1000.0 );
return arr2;
}
public static T [ ] Shuffle<T> ( T [ ] array )
{
Random rnd = new Random ( );
T [ ] newArray = new T [ array.Length ];
array.CopyTo ( newArray, 0 );
for ( int i = 0; i < array.Length; ++i )
{
int index = rnd.Next ( i, array.Length );
if ( index != i )
{
T temp = newArray [ i ];
newArray [ i ] = newArray [ index ];
newArray [ index ] = temp;
}
}
return newArray;
}
}
Light
Mine’s just your code tweaked to use the algorithm I’d posted in mxs.
I didn’t spend any time optimizing the C#, I just wanted to compare apples to apples and see how fast a compiled version ran.
fn myCreateArrAssembly =
(
source = ""
source += "using System;
"
source += "using System.Collections;
"
source += "namespace MathOps
"
source += "{
"
source += " public class myArrayClass
"
source += " {
"
source += " private Int32[] RandomizeIndexes(int count, Random list)
"
source += " {
"
source += " Int32 j;"
source += " Int32[] randoms = new Int32[count];
"
source += " randoms[0] = 1;"
source += " for (int i = 1; i < count; i++)
"
source += " {
"
source += " j = list.Next(0,i+1);"
source += " randoms[i] = randoms[j];
"
source += " randoms[j] = i+1;
"
source += " }
"
source += " return randoms;
"
source += " }
"
source += " public Int32[] RandomIndexes(int count)
"
source += " {
"
source += " Random list = new Random();
"
source += " return RandomizeIndexes(count, list);
"
source += " }
"
source += " public Int32[] RandomIndexes(int count, int seed)
"
source += " {
"
source += " Random list = new Random(seed);
"
source += " return RandomizeIndexes(count, list);
"
source += " }
"
source += " }
"
source += "}
"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.ReferencedAssemblies.AddRange #("System.dll")
compilerParams.GenerateInMemory = on
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
if (compilerResults.Errors.Count > 0 ) then
(
errs = stringstream ""
for i = 0 to (compilerResults.Errors.Count-1) do
(
err = compilerResults.Errors.Item[i]
format "Error:% Line:% Column:% %
" err.ErrorNumber err.Line \
err.Column err.ErrorText to:errs
)
MessageBox (errs as string) title: "Errors encountered while compiling C# code"
format "%
" errs
return undefined
)
assembly = compilerResults.CompiledAssembly
assembly.CreateInstance "MathOps.myArrayClass"
)
global myArrayClass = myCreateArrAssembly()
fn myrandomIndexes count seedvalue: asdotnetobject:off =
(
if not iskindof seedvalue Integer
then myArrayClass.RandomIndexes count asdotnetobject:asdotnetobject
else myArrayClass.RandomIndexes count seedvalue:seedvalue asdotnetobject:asdotnetobject
)
Is this way of compiling be faster in performance than using DotNet.LoadAssembly? It would be cool if it was (:
Cheers,
Light
it’s not faster probably. usually for small assemblies i use on-fly compiling method, for bigger but easy for debugging i use dynamic dll loading. for dlls that really need debugging i use loadassembly with complete restating of max.
on-fly compiling just allows me rebuild the assembly every time when i need it for any purpose.
Yes I tried it, it’s about 15-20ms slower.
The conversion from .NET to Mxs takes a lot of time like biddle said. If I use specify the asDotNetObject parameter as true, mine drops to 0.022s. Significant saving for sure.
Light
The vast majority of the time is spent converting the million element .NET array to MXS array:
(
gc()
local limit = 1000000
local startM = heapfree
local startT = timestamp()
local a = myrandomIndexes limit asdotnetobject:off
format "
Return an mxs array:
Time: %s, Mem: %Kb
" ((timestamp()-startT)/1000.0) (((startM-heapfree) as integer)/1024)
format "Num unique elem %
" (a as bitarray).numberset
)
(
gc()
local limit = 1000000
local startM = heapfree
local startT = timestamp()
local a = myrandomIndexes limit asdotnetobject:on
format "
Return a .NET array :
Time: %s, Mem: %Kb
" ((timestamp()-startT)/1000.0) (((startM-heapfree) as integer)/1024)
--format "Num unique elem %
" (a as bitarray).numberset
)
Return an mxs array:
Time: 1.417s, Mem: 27395Kb
Num unique elem 1000000
OK
Return a .NET array :
Time: 0.048s, Mem: 0Kb
OK
sure… that was a point for me to do c# assembly.
so we have a Winner!
biddle and his little friend – wikipedia
fn CreateArrAssembly =
(
source = ""
source += "using System;
"
source += "using System.Collections;
"
source += "namespace MathOps
"
source += "{
"
source += " public class ArrayClass
"
source += " {
"
source += " public int[] RandomIndexes(int count)
"
source += " {
"
source += " Random list = new Random();
"
source += " int[] numbers = new int[count];
"
source += " int[] randoms = new int[count];
"
source += " for (int i = 0; i < count; i++)
"
source += " {
"
source += " randoms[i] = list.Next();
"
source += " numbers[i] = i + 1;
"
source += " }
"
source += " Array.Sort(randoms, numbers);
"
source += " return numbers;
"
source += " }
"
source += " public int[] RandomSwapIndexes(int count)
"
source += " {
"
source += " Random list = new Random();
"
source += " int j;
"
source += " int[] randoms = new int[count];
"
source += " randoms[0] = 1;
"
source += " for (int i = 1; i < count; i++)
"
source += " {
"
source += " j = list.Next(0, i + 1);
"
source += " randoms[i] = randoms[j];
"
source += " randoms[j] = i + 1;
"
source += " }
"
source += " return randoms;
"
source += " }
"
--------------------------- seed support ------------------------------
source += " public int[] RandomIndexes(int count, int seed)
"
source += " {
"
source += " Random list = new Random(seed);
"
source += " int[] numbers = new int[count];
"
source += " int[] randoms = new int[count];
"
source += " for (int i = 0; i < count; i++)
"
source += " {
"
source += " randoms[i] = list.Next();
"
source += " numbers[i] = i + 1;
"
source += " }
"
source += " Array.Sort(randoms, numbers);
"
source += " return numbers;
"
source += " }
"
source += " public int[] RandomSwapIndexes(int count, int seed)
"
source += " {
"
source += " Random list = new Random(seed);
"
source += " int j;
"
source += " int[] randoms = new int[count];
"
source += " randoms[0] = 1;
"
source += " for (int i = 1; i < count; i++)
"
source += " {
"
source += " j = list.Next(0, i + 1);
"
source += " randoms[i] = randoms[j];
"
source += " randoms[j] = i + 1;
"
source += " }
"
source += " return randoms;
"
source += " }
"
source += " }
"
source += "}
"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.ReferencedAssemblies.AddRange #("System.dll")
compilerParams.GenerateInMemory = on
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
assembly = compilerResults.CompiledAssembly
assembly.CreateInstance "MathOps.ArrayClass"
)
global ArrayClass = CreateArrAssembly()
maxlimit = 1000000
fn indexDensity list parts:5 =
(
sums = 0
for k=0 to parts-1 do
(
sum = 0
for i=0 to list.count/parts-1 do
(
sum += list[k*parts + i + 1]
)
format " %: % ? %
" k sum ((maxlimit+1)*(maxlimit/2)/parts)
sums += sum
)
format " =: % % % = %
" sums "%" ((maxlimit+1)*(maxlimit/2)) (sums*1.0/((maxlimit+1)*(maxlimit/2)))
)
(
gc()
limit = maxlimit
startM = heapfree
startT = timestamp()
a = ArrayClass.RandomSwapIndexes limit 1 asdotnetobject:on
format "
Biddle algorithm (thank you wikipedia):
Time: %s, Mem: %Kb
" ((timestamp()-startT)/1000.0) (((startM-heapfree) as integer)/1024)
-- format "Num unique elem %
" (a as bitarray).numberset
-- indexDensity a
)
(
gc()
limit = maxlimit
startM = heapfree
startT = timestamp()
a = ArrayClass.RandomIndexes limit 1 asdotnetobject:on
format "
denisT code:
Time: %s, Mem: %Kb
" ((timestamp()-startT)/1000.0) (((startM-heapfree) as integer)/1024)
-- format "Num unique elem %
" (a as bitarray).numberset
-- indexDensity a
)
it’s a template for anyone who to play with
the interesting story behind… my first algorithm was very similar to biddle’s. but i refused it for some reason. i didn’t like the distribution. now i can’t see anything wrong with it.
i can’t compile Light’s code in max. is there something .net 3.5 specific? i don’t see anything.
same as Light said…
but Light and me in my research initialize an array and fill it up with sequence. Here we are loosing time and memory.