Linear Congruential generator in XQuery1.0 - xquery

I wrote (pseudo) random number generator in XQUERY 1.0 using Linear Consequential Method. It works but it is slow. Help me to improve the code:
xquery version "1.0";
(:pseudorandom number generator using Linear Congruential Method (LCM). The number generated will be less than $m :)
declare namespace mg = "https://www.linkedin.com/in/maria-kedzierski-36088513b/";
declare variable $m:= 32768; (: select $m to be power of 2 :)
declare variable $a:= 25173; (: $a=1+4k, where k is an integer and $a < $m :)
declare variable $c:= 13849; (: $c is relative prime to $m and $c < $m :)
declare variable $x0:= 16384; (: $X0 < $m :)
declare function mg:random($num as xs:integer) as xs:integer {
if ($num = 1) then (($a * $x0 + $c) mod $m) else (($a * mg:random($num - 1) + $c) mod $m) };
for $i in (1 to 100) return mg:random($i)

When I profiled the code execution in MarkLogic, the bulk of the time was spent re-calculating number that have already been generated. Leveraging maps, you can cache those calculated values.
Below is an XQuery 1.0-ml transform that uses MarkLogic map functions. It reduces the transformation time from 16ms to 1ms.
xquery version "1.0-ml";
(:pseudorandom number generator using Linear Congruential Method (LCM). The number generated will be less than $m :)
declare namespace mg = "https://www.linkedin.com/in/maria-kedzierski-36088513b/";
declare variable $m:= 32768; (: select $m to be power of 2 :)
declare variable $a:= 25173; (: $a=1+4k, where k is an integer and $a < $m :)
declare variable $c:= 13849; (: $c is relative prime to $m and $c < $m :)
declare variable $x0:= 16384; (: $X0 < $m :)
declare variable $cache := map:new();
declare function mg:random($num as xs:integer) as xs:integer {
let $key := xs:string($num)
let $cached-value := map:get($cache, $key)
return
if ($cached-value) then
$cached-value
else
let $random-value :=
if ($num = 1) then
($a * $x0 + $c) mod $m
else
($a * mg:random($num - 1) + $c) mod $m
return
(
$random-value,
map:put($cache, $key, $random-value)
)
};
for $i in (1 to 100)
return mg:random($i)
A pure XQuery 3.1 module using standard maps is below. Although MarkLogic has many 3.x language features, it does not yet allow the syntax for standard map constructors. When I profiled this module in eXist, it actually increased the time from 57ms to 151ms:
xquery version "3.1";
(:pseudorandom number generator using Linear Congruential Method (LCM). The number generated will be less than $m :)
declare namespace mg = "https://www.linkedin.com/in/maria-kedzierski-36088513b/";
declare variable $m:= 32768; (: select $m to be power of 2 :)
declare variable $a:= 25173; (: $a=1+4k, where k is an integer and $a < $m :)
declare variable $c:= 13849; (: $c is relative prime to $m and $c < $m :)
declare variable $x0:= 16384; (: $X0 < $m :)
declare variable $cache := map {};
declare function mg:random($num as xs:integer) as xs:integer {
let $key := xs:string($num)
let $cached-value := map:get($cache, $key)
return
if ($cached-value) then
$cached-value
else
let $random-value :=
if ($num = 1) then
($a * $x0 + $c) mod $m
else
($a * mg:random($num - 1) + $c) mod $m
return
(
$random-value,
map:put($cache, $key, $random-value)
)[1]
};
for $i in (1 to 100)
return mg:random($i)

Related

PHP Recursion Script is taking took long to execute HackerRank powerSum problem

Time limit exceeded
Your code did not execute within the time limits. Please optimize your code.
<?php
/*
* Complete the 'powerSum' function below.
*
* The function is expected to return an INTEGER.
* The function accepts following parameters:
* 1. INTEGER X
* 2. INTEGER N
*/
function powerSum($X, $N) {
// Write your code here
if (1 <= $X && $X <= 1000 && 2 <= $N && $N <= 10) {
$num = 1;
$list = [];
while ( true ) {
$pow = pow($num, $N);
if ($pow > $X) {break;}
$list[] = $pow;
$num ++;
}
$limit = $X;
$array = $list;
// the algorithm is usable if the number of elements is less than 20 (because set_time_limit)
$num = count($array);
//The total number of possible combinations
$total = pow($N, $num);
$out = array();
// loop through each possible combination
for ($i = 0; $i < $total; $i++) {
$comb = array();
// for each combination check if each bit is set
for ($j = 0; $j < $num; $j++) {
// is bit $j set in $i?
if (pow($N, $j) & $i){
$comb[] = $array[$j];
}
}
if (array_sum($comb) == $limit)
{
$out[] = $comb;
}
}
array_multisort(array_map('count', $out), SORT_ASC, $out);
$out = array_unique($out, SORT_REGULAR);
return count($out);
}
}
The above function is working and passing a lot of test cases but fails only due to timeout reasons.
I hope someone will help me fix this problem as soon as possible.
I ran the code on HackerRank, it ran well but failed on test case due to time.
The link to this challenge on hackerRank is:https://www.hackerrank.com/challenges/the-power-sum/problem?isFullScreen=true

Refactoring a recursive function into iterative in a coin-change type of problem

In a coin-change type of problem, I'm trying to refactor the recursive function into iterative. Given a set of coin_types, the function coinr finds the minimum number of coins to pay a given amount, sum, recursively.
# Any coin_type could be used more than once or it may not be used at all
sub coinr ($sum, #coin_types) { # As this is for learning basic programming
my $result = $sum; # No memoization (dynamic programming) is used
if $sum == #coin_types.any { return 1 }
else { for #coin_types.grep(* <= $sum) -> $coin_type {
my $current = 1 + coinr($sum - $coin_type, #coin_types);
$result = $current if $current < $result; } }
$result;
}
say &coinr(#*ARGS[0], split(' ', #*ARGS[1]));
# calling with
# 8 "1 4 5" gives 2 (4+4)
# 14 "1 3 5" gives 4 (1+3+5+5), etc.
This function was originally written in Python and I converted it to Raku. Here is my take on the iterative version, which is very incomplete:
# Iterative
sub coini ($sum, #coin_types) {
my $result = 1;
for #coin_types -> $coin_type {
for 1 ... $sum -> $i {
if $sum-$coin_type == #coin_types.any { $result += 1 } #?
else { # ???
}
}
}
}
Can somebody help me on this?
There are a number of different ways to implement this iteratively (There's More Than One Way To Do It, as we like to say!) Here's one approach:
sub coini($sum is copy, #coin-types) {
gather while $sum > 0 { take $sum -= #coin-types.grep(* ≤ $sum).max } .elems
}
This decreases the (now mutable) $sum by the largest coin possible, and keeps track of the current $sum in a list. Then, since we only want the number of coins, it returns the length of that list.

"Taking on a Challenge in SPARK Ada" - Sum ghost function in post-condition having unintended behavior

I am writing a piece of software in SPARK Ada which requires the post-condition to verify that the function return value is equal to the summed values of an array. Upon proving the file where the function resides, I keep getting an error which doesn't quite add up, no pun intended (I will post screenshots of the code so as to allow a better look). The only acceptable values allowed in the array of size 10 are 0s or 1s.
In the example below (and opposed to the other answer), I separated the ghost function that computes the partial sum into a generic ghost package SPARK_Fold. From this package I use the ghost function Sum_Acc to proof the summation loop in Calc_ST. The package Example can be proven using GNAT CE 2020 with prove level set to 1.
Credits for the underlying method: AdaCore blog post.
example.ads
with SPARK_Fold;
package Example with SPARK_Mode is
subtype EEG_Reading_Index is Integer range 0 .. Integer'Last - 1;
subtype EEG_Reading is Integer range 0 .. 1;
type EEG_Readings is array (EEG_Reading_Index range <>) of EEG_Reading;
package Sum_EEG_Readings is
new SPARK_Fold.Sum
(Index_Type => EEG_Reading_Index,
Element_In => EEG_Reading,
List_Type => EEG_Readings,
Element_Out => Natural);
function Calc_ST (EEG : EEG_Readings) return Natural with
Pre => EEG'Length > 0,
Post => Calc_ST'Result = Sum_EEG_Readings.Sum_Acc (EEG) (EEG'Last);
end Example;
example.adb (just computing the sum as usual here).
package body Example with SPARK_Mode is
-------------
-- Calc_ST --
-------------
function Calc_ST (EEG : EEG_Readings) return Natural is
Result : Natural := EEG (EEG'First);
begin
for I in EEG'First + 1 .. EEG'Last loop
pragma Loop_Invariant
(Result = Sum_EEG_Readings.Sum_Acc (EEG) (I - 1));
Result := Result + EEG (I);
end loop;
return Result;
end Calc_ST;
end Example;
spark_fold.ads (a generic helper package)
package SPARK_Fold with Ghost is
-- Based on the blog post:
-- https://blog.adacore.com/taking-on-a-challenge-in-spark
---------
-- Sum --
---------
generic
type Index_Type is range <>;
type Element_In is range <>;
type List_Type is array (Index_Type range <>) of Element_In;
type Element_Out is range <>;
package Sum with Ghost is
type Partial_Sums is array (Index_Type range <>) of Element_Out;
function Sum_Acc (L : List_Type) return Partial_Sums with
Ghost,
Pre => (L'Length > 0),
Post => (Sum_Acc'Result'Length = L'Length)
and then (Sum_Acc'Result'First = L'First)
and then (for all I in L'First .. L'Last =>
abs (Sum_Acc'Result (I)) <= Element_Out (I - L'First + 1) * Element_Out (Element_In'Last))
and then (Sum_Acc'Result (L'First) = Element_Out (L (L'First)))
and then (for all I in L'First + 1 .. L'Last =>
Sum_Acc'Result (I) = Sum_Acc'Result (I - 1) + Element_Out (L (I)));
end Sum;
-----------
-- Count --
-----------
generic
type Index_Type is range <>;
type Element is range <>;
type List_Type is array (Index_Type range <>) of Element;
with function Choose (X : Element) return Boolean;
-- Count the number of elements for which Choose returns True.
package Count with Ghost is
type Partial_Counts is array (Index_Type range <>) of Natural;
function Count_Acc (L : List_Type) return Partial_Counts with
Ghost,
Pre => (L'Length > 0),
Post => (Count_Acc'Result'Length = L'Length)
and then (Count_Acc'Result'First = L'First)
and then (for all I in L'First .. L'Last =>
Count_Acc'Result (I) <= Natural (I) - Natural (L'First) + 1)
and then (Count_Acc'Result (L'First) = (if Choose (L (L'First)) then 1 else 0))
and then (for all I in L'First + 1 .. L'Last =>
Count_Acc'Result (I) = Count_Acc'Result (I - 1) + (if Choose (L (I)) then 1 else 0));
end Count;
end SPARK_Fold;
spark_fold.adb
package body SPARK_Fold is
---------
-- Sum --
---------
package body Sum is
function Sum_Acc (L : List_Type) return Partial_Sums is
Result : Partial_Sums (L'Range) := (others => 0);
begin
Result (L'First) := Element_Out (L (L'First));
for Index in L'First + 1 .. L'Last loop
-- Head equal.
pragma Loop_Invariant
(Result (L'First) = Element_Out (L (L'First)));
-- Tail equal.
pragma Loop_Invariant
(for all I in L'First + 1 .. Index - 1 =>
Result (I) = Result (I - 1) + Element_Out (L (I)));
-- Result within bounds.
pragma Loop_Invariant
(for all I in L'First .. Index - 1 =>
abs (Result (I)) <= Element_Out (I - L'First + 1) * Element_Out (Element_In'Last));
Result (Index) := Result (Index - 1) + Element_Out (L (Index));
end loop;
return Result;
end Sum_Acc;
end Sum;
-----------
-- Count --
-----------
package body Count is
function Count_Acc (L : List_Type) return Partial_Counts is
Result : Partial_Counts (L'Range) := (others => 0);
begin
if Choose (L (L'First)) then
Result (L'First) := 1;
else
Result (L'First) := 0;
end if;
for Index in L'First + 1 .. L'Last loop
-- Head equal.
pragma Loop_Invariant
(Result (L'First) = (if Choose (L (L'First)) then 1 else 0));
-- Tail equal.
pragma Loop_Invariant
(for all I in L'First + 1 .. Index - 1 =>
Result (I) = Result (I - 1) + (if Choose (L (I)) then 1 else 0));
-- Bounds.
pragma Loop_Invariant
(for all I in L'First .. Index - 1 =>
Result (I) <= Natural (I) - Natural (L'First) + 1);
if Choose (L (Index)) then
Result (Index) := Result (Index - 1) + 1;
else
Result (Index) := Result (Index - 1) + 0;
end if;
end loop;
return Result;
end Count_Acc;
end Count;
end SPARK_Fold;
This is the fix:
function CalcST(eegR: in eegReadings) return Natural is
supT: Integer := eegR(eegR'First);
begin
-- Sums the number of ones in the array
for Index in eegR'First + 1 .. eegR'Last loop
pragma Loop_Invariant --
(supT = sumEEGR (eegR) (Index - 1));
pragma Loop_Invariant -- additional loop invariant
(supT <= Index - 1);
if eegR(Index) = 1
then supT := supT + eegR(Index);
end if;
end loop;
return supT;
end CalcST;

How to increase a number for a certain percentage (say %10) expotential number of times (say 20) and then decrease it to base value again?

I basically have a number, say 100.
I can increase it by 10 percent every time. So, :
1st run it would become 110,
2nd 121,
3rd 133 and so on.
I can have count of how much the value was increased. But how to expotentialy decrease the amount knowing the number of times it has been increased back to 100?
Is there a way to do it with simple math op like ** instead of looping the current value amount of times it has been altered by 10 percents?
I know I can just store it in additionl column like base_number=100 or something when I need the basic value, but I would like to know if its possible to do by one-liner calculations?
So your basic question is, how do you invert and find x_0 given a known n and:
x_n = x_0 * 1.1^n
Looks like we can simply divide through by 1.1^n
x_n/(1.1^n) = x_0
So you can either calculate 1.1^n with pow(1.1, n) and divide x_n (your "increased" value) by that, or just loop and reduce like you increased:
//1.
$original = $increased/pow(1.1, n);
//2.
$original = $increased;
for ($i = 0; $i < n; $i++) {
$original = $original / 1.1;
}
So in your example, let's say our $increased is known to be 133, and n=3. Then using the first method:
$original = 133 / (1.1^3) = 133 / 1.33 = 100
Let's make a simple example and try to find a formula :
100 * 1.10 = 110;
110 * 1.10 = 121;
121 * 1.10 = 133.1;
So right now we have :
basic_number (will be bn) * increase_value (will be iv) = basic_number2;
bn2 * iv = bn3;
bn3 * iv = bn4;
We can write it too :
bn * iv = bn2;
bn * iv * iv = bn3;
bn * iv * iv * iv = bn4;
And so we have the beginning of a formula :
bn * iv^3 = bn4;
Now what you will have as data according to your post is :
X : the number of increase
bnX : the basic number increase X time
iv : the increase value
And you want to find bn according to those value :
bn * iv^X = bnX;
bn = bnX / iv^X;
bn = bnX / (iv * iv * iv ... * iv); // X time
So with PHP it could look like this :
$X = /* the number of incease */;
$bnX = /* the basic number increase X time */;
$iv = /* the increase value */;
for($i = 0; $i < $X; $i++) {
$bnX = $bnX / $iv;
}
This way you will if you echo $bnX; at the end of the loop, you should get your basic number !
You can try to make a php formula to do it and use it every time :
// 1/ Using a loop
function getBasicNumber($bnX, $X, $iv) {
for($i = 0; $i < $X; $i++) {
$bnX = $bnX / $iv;
}
return $bnX;
}
EDIT
// 2/ Using pow
function getBasicNumber($bnX, $X, $iv) {
return $bnX / pow($X, $iv);
}
// 3/ Using '**'
function getBasicNumber($bnX, $X, $iv) {
return $bnX / $X**$iv;
}
This way you just have to do :
echo getBasicNumber(133.1, 3, 1.10); // 100 here for example
Hope it's clear? But still, it's more a maths problem than a programming one

Variable for adjusting the increase of a numbers value on a curve

I want to increase the value of a number on a curve. I have:
for($i=1; $i<=40; $i++){
$number = cosh($i);
echo $number;
}
This example curves up too fast. How to do I add a variable to this code that will allow me to adjust the rate the number increases? I looking to adjust the slope of the curve. I'm not looking to adjust the value of the beginning number (ie $i = $i*.3).
Countless ways to do this. Here are two:
Change the exponent of $i. Since your starting value is 1, and 1 raised to any power is still 1. Choose a power in the range (0, 1) (non-inclusive), e.g.:
$number = cosh(pow($i, 0.25));
Slightly more general - a power or a multiple of the difference between $i and starting value:
$start = 1;
$end = 40;
$const = 0.01;
for ($i = $start; $i <= $end; $i++) {
$number = cosh($start + ($i - $start) * $const);
// ...
// or...
$power = 0.25;
for ($i = $start; $i <= $end; $i++) {
$number = cosh($start + pow($i - $start, $power));
// ...
// or a combination of both.
if you don't want to change $i in the for definition, change it within the function call:
for($i=1; $i<=40; $i++){
$number = cosh($i*.3);
echo $number;
}

Resources