How to use an array as index for decision variable in cplex - network-programming

I am new in cplex. I want to use the two arrays that I have in my code as indexes for my decision variables and parameters. I need the values ​​of the arrays as indices, not the sizes of the arrays, too. I saw these links: "https://github.com/AlexFleischerParis/zooopl/blob/master/zooarrayvariableindexerunion.mod" and other examples in https://stackoverflow.com for my problem but I don't know How should I change my code?
.mod
{int} V = {11, 12, 13, 21, 22, 23, 31, 32, 33, 41, 42, 43, 51, 52, 53};
range F=1..20;
int sizeFlow[f in F]=2+rand(3);
int n=card(V);
int m=4;
range r=1..n;
// scripting way that will get m times 1
range subr=1..m;
int t[f in F][i in subr]=1+rand(n+1-i);
{int} setn[f in F]=asSet(r);
int x2[F][i in r];
execute
{
for (var f in F) for(var i in subr)
{
var e=t[f][i];
var e2=Opl.item(setn[f],e-1);
x2[f][e2]=1;
setn[f].remove(e2);
}
}
{int} result[f in F]={i | i in r:x2[f][i]==1};
{int} Flow4[f in F]=union (i in result[f]) {item(V,i-1)};
{int} Flow[f in F]={item(Flow4[f],j-1) | j in 1..sizeFlow[f]};
assert forall(f in F) forall(ordered i,j in Flow[f]) i!=j;
execute{ writeln(Flow); }
Now I want to use arrays sizeFlow[f] and Flow[f] in rest of my code, For example:
range Nunode1 = 0..10;
tuple edge{
key int origin;
key int destination;}
{edge} Edges with origin,destination in Nunode1 = {<0,1>,<1,3>,<2,3>,<3,4>,<3,5>,<3,6>,
<4,5>,<4,6>,<4,8>,<5,6>,<6,7>,<6,9>,<9,10>};
//transmission rate.
float C[Edges]=...;
float landa[Flow[f]] = 0.5 +rand(2);
//DECISION VARIABLES
dvar boolean IL[Edges][Flow[f]][sizeFlow[f]][Nunode1][sizeFlow[f]][Nunode1]; //denotes
that link l is used by flow f to route from the j-th to (j + 1)-th NF service, hosted at
node nj and nj+1.
//Objective function
dexpr float objmodel2 = sum(l in Edges, c in 1..Flow[f], j in 1..sizeFlow[f]: (j+1) in
1..sizeFlow[f] && (j+1)>j, n in Nunode1: (n+1) in Nunode1 && (n+1)>n) ((IL[l][c][j][n]
[j+1][n+1] * landa[c]) / C[l]); //to minimize the utilization of link capacities.
minimize objmodel2;
subject to{
forall (l in Edges)
cons1: sum(c in 1..Flow[f], j in 1..sizeFlow[f]: j+1 in 1..sizeFlow[f], n in Nunode1:
(n+1) in Nunode1) (IL[l][c][j][n][j+1][n+1] * landa[c]) <= C[l];}

Related

Convert partial number to written word form in Google Sheets (e.g. 1300 to 1.3 thousand)? [duplicate]

is there a way how to custom format ridiculously large numbers (at least up to 10^100 in both ways) in google sheets:
thousands > K
millions > M
billions > B
trillions > T
etc...
negative quadrillions > Q
decillions > D
either via:
internal custom number formatting
formula (array formula ofc)
script similar to this one just extended to cover more ground
10000.1 10.0K
100 100.0
1000 1.0K
10000 10.0K
-100000 -100.0K
45646454 45.6M
5654894844216 5.7T
4655454544 4.7B
46546465455511 46.5T
-46546465455511 -46.5T
4654646545551184854556546454454400000000000000000000000000010000000 4.7U
-1000.9999 -1.0K
-100.8989 -100.9
-20.354 -20.4
1.03 1.0
22E+32 2.2D
internal custom number formatting solution:
sadly, the internal formatting in google sheets is by default able to work with only 3 types of numbers:
positive (1, 2, 5, 10, ...)
negative (-3, -9, -7, ...)
zero (0)
this can be tweaked to show custom formatting like thousands K, millions M and regular small numbers:
[>999999]0.0,,"M";[>999]0.0,"K";0
or only thousands K, millions M, billions B
[<999950]0.0,"K";[<999950000]0.0,,"M";0.0,,,"B"
or only negative thousands K, negative millions M, negative billions B
[>-999950]0.0,"K";[>-999950000]0.0,,"M";0.0,,,"B"
or only millions M, billions B, trillions T:
[<999950000]0.0,,"M";[<999950000000]0.0,,,"B";0.0,,,,"T"
or only numbers from negative million M to positive million M:
[>=999950]0.0,,"M";[<=-999950]0.0,,"M";0.0,"K"
but you always got only 3 slots you can use, meaning that you can't have trillions as the 4th type/slot. fyi, the 4th slot exists, but it's reserved for text. to learn more about internal formatting in google sheets see:
https://developers.google.com/sheets/api/guides/formats#meta_instructions
https://www.benlcollins.com/spreadsheets/google-sheets-custom-number-format/
formula (array formula) solution:
the formula approach is more versatile... first, you will need to decide on the system/standard you want to use (American, European, Greek, International, Unofficial, etc...):
en.wikipedia.org/wiki/Names_of_large_numbers
en.wikipedia.org/wiki/Metric_prefix
simple.wikipedia.org/wiki/Names_for_large_numbers
home.kpn.nl/vanadovv/BignumbyN
after that try:
=INDEX(REGEXREPLACE(IFNA(TEXT(A:A/10^(VLOOKUP(LEN(TEXT(INT(ABS(A:A)), "0"))-1,
SEQUENCE(35, 1,, 3), 1, 1)), "#.0")&VLOOKUP(ABS(A:A)*1, {{10^SEQUENCE(34, 1, 3, 3)},
{"K "; "M "; "B "; "T "; "Qa "; "Qi "; "Sx "; "Sp "; "O "; "N "; "D "; "Ud ";
"Dd "; "Td "; "Qad"; "Qid"; "Sxd"; "Spd"; "Od "; "Nd "; "V "; "Uv "; "Dv "; "Tv ";
"Qav"; "Qiv"; "Sxv"; "Spv"; "Ov "; "Nv "; "Tr "; "Ut "; "Dt "; "Tt "}}, 2, 1),
IF(ISBLANK(A:A),, TEXT(A:A, "0.0 "))), "^0\.0 $", "0 "))
works with positive numbers
works with negative numbers
works with zero
works with decimal numbers
works with numeric values
works with plain text numbers
works with scientific notations
works with blank cells
works up to googol 10^104 in both ways
extra points if you are interested in how it works...
let's start with virtual array {{},{}}. SEQUENCE(34, 1, 3, 3) will give us 34 numbers in 1 column starting from number 3 with the step of 3 numbers:
these will be used as exponents while rising 10 on the power ^
so our virtual array will be:
next, we insert it as the 2nd argument of VLOOKUP where we check ABS absolute values (converting negative values into positive) of A column multiplied by *1 just in case values of A column are not numeric. via VLOOKUP we return the second 2 column and as the 4th argument, we use approximate mode 1
numbers from -999 to 999 will intentionally error out at this point so we could later use IFNA to "fix" our errors with IF(A:A=IF(,,),, TEXT(A:A, "#.0 ")) translated as: if range A:A is truly empty ISBLANK output nothing, else format A column with provided pattern #.0 eg. if cell A5 = empty, the output will be blank cell... if -999 < A5=50 < 999 the output will be 50.0
and the last part:
TEXT(A:A/10^(VLOOKUP(LEN(TEXT(INT(ABS(A:A)), "0"))-1,
SEQUENCE(35, 1,, 3), 1, 1)), "#.0")
ABS(A:A) to convert negative numbers into positive. INT to remove decimal numbers if any. TEXT(, "0") to convert scientific notations 3E+8 into regular numbers 300000000. LEN to count digits. -1 to correct for base10 notation. VLOOKUP above-constructed number in SEQUENCE of 35 numbers in 1 column, this time starting from number 0 ,, with the step of 3 numbers. return via VLOOKUP the first 1 column (eg. the sequence) in approximate mode 1 of vlookup. insert this number as exponent when rising the 10 on power ^. and take values in A column and divide it by the above-constructed number 10 raised on the power ^ of a specific exponent. and lastly, format it with TEXT as #.0
to convert ugly 0.0 into beautiful 0 we just use REGEXREPLACE. and INDEX is used instead of the longer ARRAYFORMULA.
sidenote: to remove trailing spaces (which are there to add nice alignment lol) either remove them from the formula or use TRIM right after INDEX.
script solution:
gratitude to #TheMaster for covering this
here is a mod of it:
/**
* formats various numbers according to the provided short format
* #customfunction
* #param {A1:C100} range a 2D array
* #param {[X1:Y10]} database [optional] a real/virtual 2D array
* where the odd column holds exponent of base 10
* and the even column contains format suffixes
* #param {[5]} value [optional] fix suffix to fixed length
* by padding spaces (only if the second parameter exists)
*/
// examples:
// =CSF(A1:A)
// =CSF(2:2; X5:Y10)
// =CSF(A1:3; G10:J30)
// =CSF(C:C; X:Y; 2) to use custom alignment
// =CSF(C:C; X:Y; 0) to remove alignment
// =INDEX(TRIM(CSF(A:A))) to remove alignment
// =CSF(B10:D30; {3\ "K"; 4\ "TK"}) for non-english sheets
// =CSF(E5, {2, "deci"; 3, "kilo"}) for english sheets
// =INDEX(IF(ISERR(A:A*1); A:A; CSF(A:A))) to return non-numbers
// =INDEX(IF((ISERR(A:A*1))+(ISBLANK(A:A)), A:A, CSF(A:A*1))) enforce mode
function CSF(
range,
database = [
[3, 'K' ], //Thousand
[6, 'M' ], //Million
[9, 'B' ], //Billion
[12, 'T' ], //Trillion
[15, 'Qa' ], //Quadrillion
[18, 'Qi' ], //Quintillion
[21, 'Sx' ], //Sextillion
[24, 'Sp' ], //Septillion
[27, 'O' ], //Octillion
[30, 'N' ], //Nonillion
[33, 'D' ], //Decillion
[36, 'Ud' ], //Undecillion
[39, 'Dd' ], //Duodecillion
[42, 'Td' ], //Tredecillion
[45, 'Qad'], //Quattuordecillion
[48, 'Qid'], //Quindecillion
[51, 'Sxd'], //Sexdecillion
[54, 'Spd'], //Septendecillion
[57, 'Od' ], //Octodecillion
[60, 'Nd' ], //Novemdecillion
[63, 'V' ], //Vigintillion
[66, 'Uv' ], //Unvigintillion
[69, 'Dv' ], //Duovigintillion
[72, 'Tv' ], //Trevigintillion
[75, 'Qav'], //Quattuorvigintillion
[78, 'Qiv'], //Quinvigintillion
[81, 'Sxv'], //Sexvigintillion
[84, 'Spv'], //Septenvigintillion
[87, 'Ov' ], //Octovigintillion
[90, 'Nv' ], //Novemvigintillion
[93, 'Tr' ], //Trigintillion
[96, 'Ut' ], //Untrigintillion
[99, 'Dt' ], //Duotrigintillion
[100, 'G' ], //Googol
[102, 'Tt' ], //Tretrigintillion or One Hundred Googol
],
value = 3
) {
if (
database[database.length - 1] &&
database[database.length - 1][0] !== 0
) {
database = database.reverse();
database.push([0, '']);
}
const addSuffix = num => {
const pad3 = (str = '') => str.padEnd(value, ' ');
const decim = 1 // round to decimal places
const separ = 0 // separate number and suffix
const anum = Math.abs(num);
if (num === 0)
return '0' + ' ' + ' '.repeat(separ) + ' '.repeat(decim) + pad3();
if (anum > 0 && anum < 1)
return String(num.toFixed(decim)) + ' '.repeat(separ) + pad3();
for (const [exp, suffix] of database) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(decim)
}${' '.repeat(separ) + pad3(suffix)}`;
}
};
return customFunctionRecurse_(
range, CSF, addSuffix, database, value, true
);
}
function customFunctionRecurse_(
array, mainFunc, subFunc, ...extraArgToMainFunc
) {
if (Array.isArray(array))
return array.map(e => mainFunc(e, ...extraArgToMainFunc));
else return subFunc(array);
}
sidenote 1: this script does not need to be authorized priorly to usage
sidenote 2: cell formatting needs to be set to Automatic or Number otherwise use enforce mode
extra:
convert numbers into plain text strings/words
convert array of numbers into plain text strings/words
convert custom formatted numbers into numeric numbers/values
convert text string datetime into duration value
convert text string formatted numbers into duration
convert your age into years-months-days
For almost all practical purposes we can use Intl compact format to achieve this functionality.
/**
* Utility function needed to recurse 2D arrays
*/
function customFunctionRecurse_(
array,
mainFunc,
subFunc,
...extraArgToMainFunc
) {
if (Array.isArray(array))
return array.map(e => mainFunc(e, ...extraArgToMainFunc));
else return subFunc(array);
}
/**
* Simple custom formating function using Intl
* #see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
* #customfunction
* #author TheMaster https://stackoverflow.com/users/8404453
* #param {A1:D2} numArr A 2D array
* #returns {String[][]}Compact Intl formatted 2D array
*/
function format(numArr) {
const cIntl = new Intl.NumberFormat('en-GB', {
notation: 'compact',
compactDisplay: 'short',
});
return customFunctionRecurse_(numArr, format, (num) => cIntl.format(num));
}
But for extreme ends or custom formatting, We need to use a custom script:
/**
* Formats various numbers according to the provided format
* #customfunction
* #author TheMaster https://stackoverflow.com/users/8404453
* #param {A1:D2} numArr A 2D array
* #param {X1:Y2} formatArr [optional] A format 2D real/virtual array
* with base 10 power -> suffix mapping
* eg: X1:3 Y1:K represents numbers > 10^3 should have a K suffix
* #param {3} suffixPadLength [optional] Fix suffix to fixed length by padding spaces
* #returns {String[][]} Formatted 2D array
*/
function customFormat(
numArr,
formatArr = [
/**This formatArr array is provided by
* by player0 https://stackoverflow.com/users/5632629/
* #see https://stackoverflow.com/questions/69773823#comment123503634_69809210
*/
[3, 'K'], //Thousand
[6, 'M'], //Million
[9, 'B'], //Billion
[12, 'T'], //Trillion
[15, 'Qa'], //Quadrillion
[18, 'Qi'], //Quintillion
[21, 'Sx'], //Sextillion
[24, 'Sp'], //Septillion
[27, 'O'], //Octillion
[30, 'N'], //Nonillion
[33, 'D'], //Decillion
[36, 'Ud'], //Undecillion
[39, 'Dd'], //Duodecillion
[42, 'Td'], //Tredecillion
[45, 'Qad'], //Quattuordecillion
[48, 'Qid'], //Quindecillion
[51, 'Sxd'], //Sexdecillion
[54, 'Spd'], //Septendecillion
[57, 'Od'], //Octodecillion
[60, 'Nd'], //Novemdecillion
[63, 'V'], //Vigintillion
[66, 'Uv'], //Unvigintillion
[69, 'Dv'], //Duovigintillion
[72, 'Tv'], //Trevigintillion
[75, 'Qav'], //Quattuorvigintillion
[78, 'Qiv'], //Quinvigintillion
[81, 'Sxv'], //Sexvigintillion
[84, 'Spv'], //Septenvigintillion
[87, 'Ov'], //Octovigintillion
[90, 'Nv'], //Novemvigintillion
[93, 'Tr'], //Trigintillion
[96, 'Ut'], //Untrigintillion
[99, 'Dt'], //Duotrigintillion
[102, 'G'], //Googol
],
suffixPadLength = 3,
inRecursion = false
) {
if (!inRecursion) {
formatArr = formatArr.reverse();
formatArr.push([0, '']);
}
const addSuffix = num => {
const pad3 = (str = '') => str.padEnd(suffixPadLength, ' '); //pad 3 spaces if necessary
const anum = Math.abs(num);
if (num === 0) return '0' + pad3();
if (anum > 0 && anum < 1) return String(num.toFixed(2)) + pad3();
for (const [exp, suffix] of formatArr) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(2)}${pad3(suffix)}`;
}
};
return customFunctionRecurse_(
numArr,
customFormat,
addSuffix,
formatArr,
suffixPadLength,
true
);
}
Usage:
=CUSTOMFORMAT(A1:A5,{{3,"k"};{10,"G"}})
Tells custom function to use k for numbers>10^3 and G for 10^10
Illustration:
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
/**
* Utility function needed to map 2D arrays
*/
function customFunctionRecurse_(array, mainFunc, subFunc, extraArgToMainFunc) {
if (Array.isArray(array))
return array.map((e) => mainFunc(e, extraArgToMainFunc));
else return subFunc(array);
}
/**
* Simple custom formating function using Intl
* #see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
* #customfunction
* #param {A1:D2} A 2D array
* #returns {String[][]}Compact Intl formatted 2D array
*/
function format(numArr) {
const cIntl = new Intl.NumberFormat('en-GB', {
notation: 'compact',
compactDisplay: 'short',
});
return customFunctionRecurse_(numArr, format, (num) => cIntl.format(num));
}
/**
* Formats various numbers according to the provided format
* #customfunction
* #param {A1:D2} A 2D array
* #param {X1:Y2=} [optional] A format 2D real/virtual array
* with base 10 power -> suffix mapping
* eg: X1:3 Y1:K represents numbers > 10^3 should have a K suffix
* #returns {String[][]} Formatted 2D array
*/
function customFormat(
numArr,
formatArr = [
//sample byte => kb formatting
[3, 'kb'],
[6, 'mb'],
[9, 'gb'],
[12, 'tb'],
]
) {
//console.log({ numArr, formatArr });
if (
formatArr[formatArr.length - 1] &&
formatArr[formatArr.length - 1][0] !== 0
) {
formatArr = formatArr.reverse();
formatArr.push([0, '']);
}
const addSuffix = (num) => {
const anum = Math.abs(num);
if (num === 0) return '0.00';
if (anum > 0 && anum < 1) return String(num.toFixed(2));
for (const [exp, suffix] of formatArr) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(2)}${suffix}`;
}
};
return customFunctionRecurse_(numArr, customFormat, addSuffix, formatArr);
}
console.log(
customFormat([
[
0,
1000,
153,
12883255,
235688235123,
88555552233355888,
-86555,
0.8523588055,
Math.pow(10, 15),
],
])
);
<!-- https://meta.stackoverflow.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
sometimes when we deal with nuclear physics we need to shorten the time so this is how:
=INDEX(IF(ISBLANK(A2:A),,TEXT(TRUNC(TEXT(IF(A2:A*1<1,
TEXT(A2:A*1, "0."&REPT(0, 30))*VLOOKUP(A2:A*1, {SORT({0; 1/10^SEQUENCE(9, 1, 3, 3)}),
{0; 10^SORT(SEQUENCE(9, 1, 3, 3), 1,)}}, 2, 1), TEXT(A2:A*1, REPT(0, 30))/
VLOOKUP(A2:A*1, TEXT({1; 60; 3600; 86400; 31536000; 31536000*10^SEQUENCE(8, 1, 3, 3)},
{"#", "#"})*1, 2, 1)), "0."&REPT("0", 30)), 3), "0.000")&" "&
VLOOKUP(A2:A*1, {SORT({0; 1/10^SEQUENCE(9, 1, 3, 3);
{1; 60; 3600; 86400; 31536000}; 31536000*10^SEQUENCE(8, 1, 3, 3)}), FLATTEN(SPLIT(
"s ys zs as fs ps ns μs ms s m h d y ky My Gy Ty Py Ey Zy Yy", " ",,))}, 2, 1)))
it's a simple conversion from seconds into abbreviation utilizing the International System of Units where:
in seconds
____________________________________
ys = yoctosecond = 0.000000000000000000000001
zs = zeptosecond = 0.000000000000000000001
as = attosecond = 0.000000000000000001
fs = femtosecond = 0.000000000000001
ps = pikosecond = 0.000000000001
ns = nanosecond = 0.000000001
μs = microsecond = 0.000001
ms = millisecond = 0.001
s = second = 1
m = minute = 60
h = hour = 3600
d = day = 86400
y = year = 31536000
ky = kiloyear = 31536000000
My = megayear = 31536000000000
Gy = gigayear = 31536000000000000
Ty = terayear = 31536000000000000000
Py = petayear = 31536000000000000000000
Ey = exayear = 31536000000000000000000000
Zy = zettayear = 31536000000000000000000000000
Yy = yottayear = 31536000000000000000000000000000

How can I generate a unique, predictable, repeatable, non sequential alphanumeric identifier?

I have to generate identifiers composed of four alphanumerical characters, e.g. B41F.
I have the following requirements:
Each identifier must be unique (there is no central location to lookup existing identifiers)
The identifier must not be obviously sequential (e.g. 1A01, 1A02)
It must be predictable
It must be repeatable using solely the identifier index (on two different environment, the Nth identifier generated, which has index N, must be the same)
The problem is generic to any language. My implementation will be done in dart.
I think this could be done with a PRNG and some LUT, but I could not find any implementation or pseudo-code that respects requirement 4) without replaying the whole sequence. Also, some PRNG implementation have a random component that is not guaranteed to be repeatable over library update.
How can I achieve this? I'm looking for pseudo-code, code or hints.
You should not use a PRNG when identifiers must be unique. RNGs do not promise uniqueness. Some might have a long period before they repeat, but that's at their full bit-range, reducing it to a smaller number may cause conflicts earlier.
Your identifiers are really just numbers in base 36, so you need something like shuffle(index).toRadixString(36) to generate it.
The tricky bit is the shuffle function which must be a permutations of the numbers 0..36^4-1, one which looks random (non-sequential), but can be computed (efficiently?) for any input.
Since 36^4 is not a power of 2, most of the easy bit-shuffles likely won't work.
If you can live with 32^4 numbers only (2^20 ~ 1M) it might be easier.
Then you can also choose to drop O, I, 0 and 1 from the result, which might make it easier to read.
In that case, I'd do something primitive (not cryptographically secure at all), like:
// Represent 20-bit numbers
String represent(int index) {
RangeError.checkValueInInterval(index, 0, 0xFFFFF, "index");
var digits = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
return "${digits[(index >> 15) & 31]}${digits[(index >> 10) & 31]}"
"${digits[(index >> 5) & 31]}${digits[index & 31]}";
}
// Completely naive number shuffler for 20-bit numbers.
// All numbers made up on the spot.
int shuffle(int index) {
RangeError.checkValueInInterval(index, 0, 0xFFFFF, "index");
index ^= 0x35712;
index ^= index << 15;
index ^= index << 4;
index ^= index << 12;
index ^= index << 7;
index ^= index << 17;
return index & 0xFFFFF; // 20 bit only.
}
If you really want the full 36^4 range to be used, I'd probably do something like the shuffle, but in base-six arithmetic. Maybe:
String represent(int index) =>
RangeError.checkValueInInterval(index, 0, 1679615, "index")
.toRadixString(36).toUpperCase();
int shuffle(int index) {
RangeError.checkValueInInterval(index, 0, 1679615, "index");
const seed = [1, 4, 2, 5, 0, 3, 1, 4]; // seed.
var digits = List<int>.filled(8, 0);
for (var i = 0; i < 8; i++) {
digits[i] = index.remainder(6);
index = index ~/ 6;
}
void shiftAdd(List<int> source, int shift, int times) {
for (var n = digits.length - 1 - shift; n >= 0; n--) {
digits[shift + n] = (digits[shift + n] + source[n] * times).remainder(6);
}
}
shiftAdd(seed, 0, 1);
shiftAdd(digits, 3, 2);
shiftAdd(digits, 5, 1);
shiftAdd(digits, 2, 5);
var result = 0;
for (var i = digits.length - 1; i >= 0; i--) {
result = result * 6 + digits[i];
}
return result;
}
Again, this is something I made up on the spot, it "shuffles", but does not promise anything about the properties of the result, other than that they don't look sequential.

Why doesn't this Fibonacci Number function work in O(log N)?

So the Fibonacci number for log (N) — without matrices.
Ni // i-th Fibonacci number
= Ni-1 + Ni-2 // by definition
= (Ni-2 + Ni-3) + Ni-2 // unwrap Ni-1
= 2*Ni-2 + Ni-3 // reduce the equation
= 2*(Ni-3 + Ni-4) + Ni-3 //unwrap Ni-2
// And so on
= 3*Ni-3 + 2*Ni-4
= 5*Ni-4 + 3*Ni-5
= 8*Ni-5 + 5*Ni-6
= Nk*Ni-k + Nk-1*Ni-k-1
Now we write a recursive function, where at each step we take k~=I/2.
static long N(long i)
{
if (i < 2) return 1;
long k=i/2;
return N(k) * N(i - k) + N(k - 1) * N(i - k - 1);
}
Where is the fault?
You get a recursion formula for the effort: T(n) = 4T(n/2) + O(1). (disregarding the fact that the numbers get bigger, so the O(1) does not even hold). It's clear from this that T(n) is not in O(log(n)). Instead one gets by the master theorem T(n) is in O(n^2).
Btw, this is even slower than the trivial algorithm to calculate all Fibonacci numbers up to n.
The four N calls inside the function each have an argument of around i/2. So the length of the stack of N calls in total is roughly equal to log2N, but because each call generates four more, the bottom 'layer' of calls has 4^log2N = O(n2) Thus, the fault is that N calls itself four times. With only two calls, as in the conventional iterative method, it would be O(n). I don't know of any way to do this with only one call, which could be O(log n).
An O(n) version based on this formula would be:
static long N(long i) {
if (i<2) {
return 1;
}
long k = i/2;
long val1;
long val2;
val1 = N(k-1);
val2 = N(k);
if (i%2==0) {
return val2*val2+val1*val1;
}
return val2*(val2+val1)+val1*val2;
}
which makes 2 N calls per function, making it O(n).
public class fibonacci {
public static int count=0;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
System.out.println("value of i ="+ i);
int result = fun(i);
System.out.println("final result is " +result);
}
public static int fun(int i) {
count++;
System.out.println("fun is called and count is "+count);
if(i < 2) {
System.out.println("function returned");
return 1;
}
int k = i/2;
int part1 = fun(k);
int part2 = fun(i-k);
int part3 = fun(k-1);
int part4 = fun(i-k-1);
return ((part1*part2) + (part3*part4)); /*RESULT WILL BE SAME FOR BOTH METHODS*/
//return ((fun(k)*fun(i-k))+(fun(k-1)*fun(i-k-1)));
}
}
I tried to code to problem defined by you in java. What i observed is that complexity of above code is not completely O(N^2) but less than that.But as per conventions and standards the worst case complexity is O(N^2) including some other factors like computation(division,multiplication) and comparison time analysis.
The output of above code gives me information about how many times the function
fun(int i) computes and is being called.
OUTPUT
So including the time taken for comparison and division, multiplication operations, the worst case time complexity is O(N^2) not O(LogN).
Ok if we use Analysis of the recursive Fibonacci program technique.Then we end up getting a simple equation
T(N) = 4* T(N/2) + O(1)
where O(1) is some constant time.
So let's apply Master's method on this equation.
According to Master's method
T(n) = aT(n/b) + f(n) where a >= 1 and b > 1
There are following three cases:
If f(n) = Θ(nc) where c < Logba then T(n) = Θ(nLogba)
If f(n) = Θ(nc) where c = Logba then T(n) = Θ(ncLog n)
If f(n) = Θ(nc) where c > Logba then T(n) = Θ(f(n))
And in our equation a=4 , b=2 & c=0.
As case 1 c < logba => 0 < 2 (which is log base 2 and equals to 2) is satisfied
hence T(n) = O(n^2).
For more information about how master's algorithm works please visit: Analysis of Algorithms
Your idea is correct, and it will perform in O(log n) provided you don't compute the same formula
over and over again. The whole point of having N(k) * N(i-k) is to have (k = i - k) so you only have to compute one instead of two. But if you only call recursively, you are performing the computation twice.
What you need is called memoization. That is, store every value that you already have computed, and
if it comes up again, then you get it in O(1).
Here's an example
const int MAX = 10000;
// memoization array
int f[MAX] = {0};
// Return nth fibonacci number using memoization
int fib(int n) {
// Base case
if (n == 0)
return 0;
if (n == 1 || n == 2)
return (f[n] = 1);
// If fib(n) is already computed
if (f[n]) return f[n];
// (n & 1) is 1 iff n is odd
int k = n/2;
// Applying your formula
f[n] = fib(k) * fib(n - k) + fib(k - 1) * fib(n - k - 1);
return f[n];
}

Hashfunction to map combinations of 5 to 7 cards

Referring to the original problem: Optimizing hand-evaluation algorithm for Poker-Monte-Carlo-Simulation
I have a list of 5 to 7 cards and want to store their value in a hashtable, which should be an array of 32-bit-integers and directly accessed by the hashfunctions value as index.
Regarding the large amount of possible combinations in a 52-card-deck, I don't want to waste too much memory.
Numbers:
7-card-combinations: 133784560
6-card-combinations: 20358520
5-card-combinations: 2598960
Total: 156.742.040 possible combinations
Storing 157 million 32-bit-integer values costs about 580MB. So I would like to avoid increasing this number by reserving memory in an array for values that aren't needed.
So the question is: How could a hashfunction look like, that maps each possible, non duplicated combination of cards to a consecutive value between 0 and 156.742.040 or at least comes close to it?
Paul Senzee has a great post on this for 7 cards (deleted link as it is broken and now points to a NSFW site).
His code is basically a bunch of pre-computed tables and then one function to look up the array index for a given 7-card hand (represented as a 64-bit number with the lowest 52 bits signifying cards):
inline unsigned index52c7(unsigned __int64 x)
{
const unsigned short *a = (const unsigned short *)&x;
unsigned A = a[3], B = a[2], C = a[1], D = a[0],
bcA = _bitcount[A], bcB = _bitcount[B], bcC = _bitcount[C], bcD = _bitcount[D],
mulA = _choose48x[7 - bcA], mulB = _choose32x[7 - (bcA + bcB)], mulC = _choose16x[bcD];
return _offsets52c[bcA] + _table4[A] * mulA +
_offsets48c[ (bcA << 4) + bcB] + _table [B] * mulB +
_offsets32c[((bcA + bcB) << 4) + bcC] + _table [C] * mulC +
_table [D];
}
In short, it's a bunch of lookups and bitwise operations powered by pre-computed lookup tables based on perfect hashing.
If you go back and look at this website, you can get the perfect hash code that Senzee used to create the 7-card hash and repeat the process for 5- and 6-card tables (essentially creating a new index52c7.h for each). You might be able to smash all 3 into one table, but I haven't tried that.
All told that should be ~628 MB (4 bytes * 157 M entries). Or, if you want to split it up, you can map it to 16-bit numbers (since I believe most poker hand evaluators only need 7,462 unique hand scores) and then have a separate map from those 7,462 hand scores to whatever hand categories you want. That would be 314 MB.
Here's a different answer based on the colex function concept. It works with bitsets that are sorted in descending order. Here's a Python implementation (both recursive so you can see the logic and iterative). The main concept is that, given a bitset, you can always calculate how many bitsets there are with the same number of set bits but less than (in either the lexicographical or mathematical sense) your given bitset. I got the idea from this paper on hand isomorphisms.
from math import factorial
def n_choose_k(n, k):
return 0 if n < k else factorial(n) // (factorial(k) * factorial(n - k))
def indexset_recursive(bitset, lowest_bit=0):
"""Return number of bitsets with same number of set bits but less than
given bitset.
Args:
bitset (sequence) - Sequence of set bits in descending order.
lowest_bit (int) - Name of the lowest bit. Default = 0.
>>> indexset_recursive([51, 50, 49, 48, 47, 46, 45])
133784559
>>> indexset_recursive([52, 51, 50, 49, 48, 47, 46], lowest_bit=1)
133784559
>>> indexset_recursive([6, 5, 4, 3, 2, 1, 0])
0
>>> indexset_recursive([7, 6, 5, 4, 3, 2, 1], lowest_bit=1)
0
"""
m = len(bitset)
first = bitset[0] - lowest_bit
if m == 1:
return first
else:
t = n_choose_k(first, m)
return t + indexset_recursive(bitset[1:], lowest_bit)
def indexset(bitset, lowest_bit=0):
"""Return number of bitsets with same number of set bits but less than
given bitset.
Args:
bitset (sequence) - Sequence of set bits in descending order.
lowest_bit (int) - Name of the lowest bit. Default = 0.
>>> indexset([51, 50, 49, 48, 47, 46, 45])
133784559
>>> indexset([52, 51, 50, 49, 48, 47, 46], lowest_bit=1)
133784559
>>> indexset([6, 5, 4, 3, 2, 1, 0])
0
>>> indexset([7, 6, 5, 4, 3, 2, 1], lowest_bit=1)
0
"""
m = len(bitset)
g = enumerate(bitset)
return sum(n_choose_k(bit - lowest_bit, m - i) for i, bit in g)

Understanding the indexing of bound variables in Z3

I am trying to understand how the bound variables are indexed in z3.
Here in a snippet in z3py and the corresponding output. ( http://rise4fun.com/Z3Py/plVw1 )
x, y = Ints('x y')
f1 = ForAll(x, And(x == 0, Exists(y, x == y)))
f2 = ForAll(x, Exists(y, And(x == 0, x == y)))
print f1.body()
print f2.body()
Output:
ν0 = 0 ∧ (∃y : ν1 = y)
y : ν1 = 0 ∧ ν1 = y
In f1, why is the same bound variable x has different index.(0 and 1). If I modify the f1 and bring out the Exists, then x has the same index(0).
Reason I want to understand the indexing mechanism:
I have a FOL formula represented in a DSL in scala that I want to send to z3. Now ScalaZ3 has a mkBound api for creating bound variables that takes index and sort as arguments. I am not sure what value should I pass to the index argument. So, I would like to know the following:
If I have two formulas phi1 and phi2 with maximum bound variable indexes n1 and n2, what would be the index of x in ForAll(x, And(phi1, phi2))
Also, is there a way to show all the variables in an indexed form? f1.body() just shows me x in indexed form and not y. (I think the reason is that y is still bound in f1.body())
Z3 encodes bound variables using de Bruijn indices.
The following wikipedia article describes de Bruijn indices in detail:
http://en.wikipedia.org/wiki/De_Bruijn_index
Remark: in the article above the indices start at 1, in Z3, they start at 0.
Regarding your second question, you can change the Z3 pretty printer.
The Z3 distribution contains the source code of the Python API. The pretty printer is implemented in the file python\z3printer.py.
You just need to replace the method:
def pp_var(self, a, d, xs):
idx = z3.get_var_index(a)
sz = len(xs)
if idx >= sz:
return seq1('Var', (to_format(idx),))
else:
return to_format(xs[sz - idx - 1])
with
def pp_var(self, a, d, xs):
idx = z3.get_var_index(a)
return seq1('Var', (to_format(idx),))
If you want to redefine the HTML pretty printer, you should also replace.
def pp_var(self, a, d, xs):
idx = z3.get_var_index(a)
sz = len(xs)
if idx >= sz:
# 957 is the greek letter nu
return to_format('ν<sub>%s</sub>' % idx, 1)
else:
return to_format(xs[sz - idx - 1])
with
def pp_var(self, a, d, xs):
idx = z3.get_var_index(a)
return to_format('ν<sub>%s</sub>' % idx, 1)

Resources