Skip to content

Commit

Permalink
Dev: Add new column 'seed' to dynamic survey table
Browse files Browse the repository at this point in the history
  • Loading branch information
olleharstedt committed Aug 30, 2016
1 parent 9c9a64c commit 2a7f83c
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 1 deletion.
3 changes: 3 additions & 0 deletions application/helpers/admin/activate_helper.php
Expand Up @@ -273,6 +273,9 @@ function activateSurvey($iSurveyID, $simulate = false)
{
switch($aRow['type'])
{
case 'seed':
$aTableDefinition[$aRow['fieldname']] = "string(31)";
break;
case 'startlanguage':
$aTableDefinition[$aRow['fieldname']] = "string(20) NOT NULL";
break;
Expand Down
8 changes: 8 additions & 0 deletions application/helpers/common_helper.php
Expand Up @@ -1810,6 +1810,14 @@ function createFieldMap($surveyid, $style='short', $force_refresh=false, $questi
$fieldmap["startlanguage"]['group_name']="";
}

$fieldmap['seed'] = array('fieldname' => 'seed', 'sid' => $surveyid, 'type' => 'seed', 'gid' => '', 'qid' => '', 'aid' => '');
if ($style == 'full')
{
$fieldmap["seed"]['title']="";
$fieldmap["seed"]['question']=gT("Seed");
$fieldmap["seed"]['group_name']="";
}

//Check for any additional fields for this survey and create necessary fields (token and datestamp and ipaddr)
$prow = Survey::model()->findByPk($surveyid)->getAttributes(); //Checked

Expand Down
5 changes: 5 additions & 0 deletions application/helpers/frontend_helper.php
Expand Up @@ -11,6 +11,9 @@
* See COPYRIGHT.php for copyright notices and details.
*/

// TODO: Why needed?
require_once(Yii::app()->basePath . '/libraries/MersenneTwister.php');

function loadanswers()
{
Yii::trace('start', 'survey.loadanswers');
Expand Down Expand Up @@ -1060,6 +1063,8 @@ function buildsurveysession($surveyid,$preview=false)
$qtypes=getQuestionTypeList('','array');
$fieldmap=createFieldMap($surveyid,'full',true,false,$_SESSION['survey_'.$surveyid]['s_lang']);

$seed = ls\mersenne\getSeed($surveyid, $preview);

// Randomization groups for groups
list($fieldmap, $randomized1) = randomizationGroup($surveyid, $fieldmap, $preview);

Expand Down
109 changes: 109 additions & 0 deletions application/libraries/MersenneTwister.php
@@ -0,0 +1,109 @@
<?php

namespace ls\mersenne;

/**
* Get seed for this answer
* If there is no seed create a new one
* @param int $surveyId
* @param boolean $preview
* @return int
*/
function getSeed($surveyId, $preview)
{
$columnNames = \SurveyDynamic::model($surveyId)->getTableSchema()->getColumnNames();
traceVar($columnNames);
// Get columns
// Check if we have seed column
// Yes: check value
// have value, use it
// no value, generate new seed
// No: create column
// generate seed
// insert seed
// Use seed to instantiate twister
}

/**
* Shuffle with seed
* @param array $arr
* @param $seed
* @return array
*/
function shuffle($arr, $seed=-1)
{
if ( $seed == -1 ) return $arr;
$mt = new MersenneTwister($seed);
$new = $arr;
for ($i = count($new) - 1; $i > 0; $i--)
{
$j = $mt->getNext(0,$i);
$tmp = $new[$i];
$new[$i] = $new[$j];
$new[$j] = $tmp;
}
return $new;
}

/**
* Custom random algorithm to get consistent behaviour between PHP versions.
*
* Copied from: http://www.dr-chuck.com/csev-blog/2015/09/a-mersenne_twister-implementation-in-php/
*/
class MersenneTwister
{
private $state = array ();
private $index = 0;

public function __construct($seed = null) {
if ($seed === null)
$seed = mt_rand();

$this->setSeed($seed);
}

public function setSeed($seed) {
$this->state[0] = $seed & 0xffffffff;

for ($i = 1; $i < 624; $i++) {
$this->state[$i] = (((0x6c078965 * ($this->state[$i - 1] ^ ($this->state[$i - 1] >> 30))) + $i)) & 0xffffffff;
}

$this->index = 0;
}

private function generateTwister() {
for ($i = 0; $i < 624; $i++) {
$y = (($this->state[$i] & 0x1) + ($this->state[$i] & 0x7fffffff)) & 0xffffffff;
$this->state[$i] = ($this->state[($i + 397) % 624] ^ ($y >> 1)) & 0xffffffff;

if (($y % 2) == 1) {
$this->state[$i] = ($this->state[$i] ^ 0x9908b0df) & 0xffffffff;
}
}
}

public function getNext($min = null, $max = null) {
if (($min === null && $max !== null) || ($min !== null && $max === null))
throw new Exception('Invalid arguments');

if ($this->index === 0) {
$this->generateTwister();
}

$y = $this->state[$this->index];
$y = ($y ^ ($y >> 11)) & 0xffffffff;
$y = ($y ^ (($y << 7) & 0x9d2c5680)) & 0xffffffff;
$y = ($y ^ (($y << 15) & 0xefc60000)) & 0xffffffff;
$y = ($y ^ ($y >> 18)) & 0xffffffff;

$this->index = ($this->index + 1) % 624;

if ($min === null && $max === null)
return $y;

$range = abs($max - $min);

return min($min, $max) + ($y % ($range + 1));
}
}
2 changes: 1 addition & 1 deletion application/models/SurveyDynamic.php
Expand Up @@ -540,7 +540,7 @@ public function getTokenForGrid()
// Get the list of default columns for surveys
public function getDefaultColumns()
{
return array('id', 'token', 'submitdate', 'lastpage','startlanguage', 'completed');
return array('id', 'token', 'submitdate', 'lastpage','startlanguage', 'completed', 'seed');
}

/**
Expand Down

0 comments on commit 2a7f83c

Please sign in to comment.