I am trying to insert approximately 200k of records with Symfony2 and Doctrine via Doctrine Fixtures Bundle. I am using flush and clear but at the end script uses 1.8 GB of RAM.
This is the class that loads SmartMeter entities into database:
<?php
namespace HTEC\SmartMeteringAPIBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use HTEC\SmartMeteringAPIBundle\Entity\SmartMeter;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class LoadSmartMeterData extends AbstractFixture implements FixtureInterface, ContainerAwareInterface, OrderedFixtureInterface
{
static $NUMBER_OF_SMART_METERS = 0;
static $MAX_NUM_OF_SM_PER_CONC = 500;
/**
* #var ContainerInterface
*/
private $container;
public function getOrder()
{
return 10; // the order in which fixtures will be loaded
}
/**
* #inheritDoc
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager)
{
$numberOfUsers = LoadUserData::$NUMBER_OF_USERS;
$numberOfConcentrators = LoadConcentratorData::$NUMBER_OF_CONCENTRATORS;
$numberOfTariffs = LoadTariffData::$NUMBER_OF_TARIFFS;
$numberOfSmartMetersPerConcentrator = 0;
$smartMeter = null;
$concentrator = null;
$user = null;
$tariff = null;
$feeders = array();
$numberOfFeeders = 0;
$feedersRandomKey = array();
$isIpAddressDynamic = false;
$numberOfTransformerFeeders = 0;
$smartMeterType = 0;
$smartMeterProtocol = 0;
$modemType = 0;
$numberOfSmartMeters = 0;
echo "\n\nCreating Smart Meters. This could take a couple of minutes and could take approximately 2 GB of RAM \n\n...";
$startTime = time();
$smartMeterCount = 0;
$lastChunkNumber = 0;
$currentChunkNumber = 0;
$lastSmartMeterNumber = 0;
$smartMetersClearedCurrently = 0;
$concentratorSmartMeters = null;
for($i = 0; $i < LoadConcentratorData::$NUMBER_OF_CONCENTRATORS; $i++)
{
$concentrator = $manager->getRepository('SMAPIBundle:Concentrator')->find($i+1);
$numberOfSmartMetersPerConcentrator = rand(1, self::$MAX_NUM_OF_SM_PER_CONC);
$numberOfSmartMeters += $numberOfSmartMetersPerConcentrator;
for($c = 0; $c < $numberOfSmartMetersPerConcentrator; $c++)
{
$smartMeter = new SmartMeter();
$smartMeter->setSerialNumber(++$smartMeterCount);
$smartMeter->setConcentrator($concentrator);
$smartMeterType = rand(1,3);
switch($smartMeterType)
{
case 1:
$smartMeter->setType('DIRECT');
break;
case 2:
$smartMeter->setType('HALF');
break;
case 3:
$smartMeter->setType('INDIRECT');
break;
}
$user = $manager->getRepository('SMAPIBundle:User')->find(rand(1, $numberOfUsers));
$smartMeter->setCreatedBy($user);
$numberOfTransformerFeeders = $concentrator->getTransformerFeeders()->count();
$feeders = $concentrator->getTransformerFeeders()->toArray();
if($numberOfTransformerFeeders > 0)
{
$feedersRandomKey = array_rand($feeders, 1);
if(isset($feeders[$feedersRandomKey]))
{
$smartMeter->setFeeder($feeders[$feedersRandomKey]);
}
}
$smartMeter->setStatus(rand(0,2));
$tariff = $manager->getRepository('SMAPIBundle:Tariff')->find(rand(1, $numberOfTariffs));
$smartMeter->setTariff($tariff);
$smartMeterProtocol = rand(1,3);
switch($smartMeterProtocol)
{
case 1:
$smartMeter->setProtocol('DLMS');
break;
case 2:
$smartMeter->setProtocol('EURIDIS');
break;
case 3:
$smartMeter->setProtocol('IEC');
break;
}
$smartMeter->setModemSerialNumber(rand(1, 9000000000));
$smartMeter->setManufacture('MAN: ' . ($i + $c));
$modemType = rand(1,2);
if($modemType === 1)
{
$smartMeter->setModemType('PLC');
$smartMeter->setModemIndex(rand(1, 512));
}
else
{
$smartMeter->setModemType('GPRS');
$isIpAddressDynamic = rand(0,1);
if($isIpAddressDynamic === 1)
{
$smartMeter->setModemIpAddress(rand(1000000, 2000000));
}
else
{
$smartMeter->setModemPhoneNumber($this->getRandomIpAddressV4());
}
}
if(rand(0,1) === 1)
{
$smartMeter->setModemRepeaterNumber(rand(10000000, 90000000));
}
$manager->persist($smartMeter);
} // end of FOR numberOfSmartMetersPerConcentrator
// flush smart meters
$manager->flush();
$manager->clear();
$currentChunkNumber = ceil($smartMeterCount / 5000);
if($smartMeterCount > 5000 && $currentChunkNumber > $lastChunkNumber)
{
$lastChunkNumber = $currentChunkNumber;
if($lastSmartMeterNumber > 0)
{
$smartMetersClearedCurrently = $smartMeterCount - $lastSmartMeterNumber;
}
else
{
$smartMetersClearedCurrently = $smartMeterCount;
}
echo "\n\nFlushing and clearing " . number_format($smartMetersClearedCurrently, 0, ',', '.') . " Smart Meters.\nTotal memory used after flush and clear: " . number_format(((memory_get_usage(true) / 1024) / 1024), 2, ',', '.') . " Megabytes\n\n...";
$lastSmartMeterNumber = $smartMeterCount;
}
}// end for NUMBER_OF_CONCENTRATORS
$manager->flush();
$manager->clear();
unset($concentrator);
unset($smartMeter);
unset($tariff);
echo "\n\n-------------------------------------------\n\n";
echo "\n\nTotal memory used after final flush and clear of Smart Meters: " . number_format(((memory_get_usage(true) / 1024) / 1024), 2, ',', '.') . " Megabytes\n\n...";
echo "\n\nCreating Smart Meters complete. Created " . number_format($numberOfSmartMeters, 0, ',', '.') . " Smart Meters.\n\n";
$durationSeconds = (time() - $startTime);
$durationMinutes = $durationSeconds / 60;
$secondsRemainder = $durationSeconds % 60;
echo "\n\nTotal duration time: " . ceil($durationMinutes) . " minutes and " . $secondsRemainder . " seconds.\n\n\n";
self::$NUMBER_OF_SMART_METERS = $numberOfSmartMeters;
}
public function getRandomIpAddressV4()
{
return rand(1, 255) . '.' . rand(0, 255) . '.' . rand(0, 255) . '.' . rand(0, 255);
}
}
On approximately 5000 records I am calling flush and clear but it seams that no memory is released.
Are there recommendations about how to prevent Doctrine from using too much RAM during batch tasks?
If it is a command, try running it with the option --no-debug. Or, you can disable the logger by calling $manager->getConnection()->getConfiguration()->setSQLLogger(null); at the beginning of your loadfunction.
Either way disabling the logger saves quite a lot of memory during Doctrine batch tasks.
Related
I'd like to learn about neural nets starting with the very basic perceptron algorithm. So I've implemented one in PHP and I'm getting weird results after training it. All the 4 possible input combinations return either wrong or correct results (more often the wrong ones).
1) Is there something wrong with my implementation or the results I'm getting are normal?
2) Can this kind of implementation work with more than 2 inputs?
3) What would be the next (easiest) step in learning neural nets after this? Maybe adding more neurons, changing the activation function, or ...?
P.S. I'm pretty bad at math and don't necessarily understand the math behind perceptron 100%, at least not the training part.
Perceptron Class
<?php
namespace Perceptron;
class Perceptron
{
// Number of inputs
protected $n;
protected $weights = [];
protected $bias;
public function __construct(int $n)
{
$this->n = $n;
// Generate random weights for each input
for ($i = 0; $i < $n; $i++) {
$w = mt_rand(-100, 100) / 100;
array_push($this->weights, $w);
}
// Generate a random bias
$this->bias = mt_rand(-100, 100) / 100;
}
public function sum(array $inputs)
{
$sum = 0;
for ($i = 0; $i < $this->n; $i++) {
$sum += ($inputs[$i] * $this->weights[$i]);
}
return $sum + $this->bias;
}
public function activationFunction(float $sum)
{
return $sum < 0.0 ? 0 : 1;
}
public function predict(array $inputs)
{
$sum = $this->sum($inputs);
return $this->activationFunction($sum);
}
public function train(array $trainingSet, float $learningRate)
{
foreach ($trainingSet as $row) {
$inputs = array_slice($row, 0, $this->n);
$correctOutput = $row[$this->n];
$output = $this->predict($inputs);
$error = $correctOutput - $output;
// Adjusting the weights
$this->weights[0] = $this->weights[0] + ($learningRate * $error);
for ($i = 0; $i < $this->n - 1; $i++) {
$this->weights[$i + 1] =
$this->weights[$i] + ($learningRate * $inputs[$i] * $error);
}
}
// Adjusting the bias
$this->bias += ($learningRate * $error);
}
}
Main File
<?php
require_once 'vendor/autoload.php';
use Perceptron\Perceptron;
// Create a new perceptron with 2 inputs
$perceptron = new Perceptron(2);
// Test the perceptron
echo "Before training:\n";
$output = $perceptron->predict([0, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([0, 1]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 1]);
echo "{$output} - " . ($output == 1 ? 'correct' : 'nope') . "\n";
// Train the perceptron
$trainingSet = [
// The 3rd column is the correct output
[0, 0, 0],
[0, 1, 0],
[1, 0, 0],
[1, 1, 1],
];
for ($i = 0; $i < 1000; $i++) {
$perceptron->train($trainingSet, 0.1);
}
// Test the perceptron again - now the results should be correct
echo "\nAfter training:\n";
$output = $perceptron->predict([0, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([0, 1]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";
$output = $perceptron->predict([1, 1]);
echo "{$output} - " . ($output == 1 ? 'correct' : 'nope') . "\n";
I must thank you for posting this question, I have wanted a chance to dive a little deeper into neural networks. Anyway, down to business. After tinkering around and verbose logging what all is happening, it ended up only requiring 1 character change to work as intended:
public function sum(array $inputs)
{
...
//instead of multiplying the input by the weight, we should be adding the weight
$sum += ($inputs[$i] + $this->weights[$i]);
...
}
With that change, 1000 iterations of training ends up being overkill.
One bit of the code was confusing, different setting of weights:
public function train(array $trainingSet, float $learningRate)
{
foreach ($trainingSet as $row) {
...
$this->weights[0] = $this->weights[0] + ($learningRate * $error);
for ($i = 0; $i < $this->n - 1; $i++) {
$this->weights[$i + 1] =
$this->weights[$i] + ($learningRate * $inputs[$i] * $error);
}
}
I don't necessarily understand why you chose to do it this way. My unexperienced eye would think that the following would work as well.
for ($i = 0; $i < $this->n; $i++) {
$this->weight[$i] += $learningRate * $error;
}
Found my silly mistake, I wasn't adjusting the bias for each row of a training set as I accidentally put it outside the foreach loop. This is what the train() method should look like:
public function train(array $trainingSet, float $learningRate)
{
foreach ($trainingSet as $row) {
$inputs = array_slice($row, 0, $this->n);
$correctOutput = $row[$this->n];
$output = $this->predict($inputs);
$error = $correctOutput - $output;
// Adjusting the weights
for ($i = 0; $i < $this->n; $i++) {
$this->weights[$i] += ($learningRate * $inputs[$i] * $error);
}
// Adjusting the bias
$this->bias += ($learningRate * $error);
}
}
Now I get the correct results after training each time I run the script. Just 100 epochs of training is enough.
I was looking for a quick way to calculate the median of a list of numbers and came across this:
function array_median($array) {
// perhaps all non numeric values should filtered out of $array here?
$iCount = count($array);
if ($iCount == 0) {
return null;
}
// if we're down here it must mean $array
// has at least 1 item in the array.
$middle_index = floor($iCount / 2);
sort($array, SORT_NUMERIC);
$median = $array[$middle_index]; // assume an odd # of items
// Handle the even case by averaging the middle 2 items
if ($iCount % 2 == 0) {
$median = ($median + $array[$middle_index - 1]) / 2;
}
return $median;
}
This approach using sort() makes sense and is certainly the obvious approach. However, I was curious if a median heap would be faster. What was surprising was that when I implemented a simple median heap it is consistently significantly slower than the above method.
My simple MedianHeap class:
class MedianHeap{
private $lowerHeap;
private $higherHeap;
private $numbers = [];
public function __construct($numbers = null)
{
$this->lowerHeap = new SplMaxHeap();
$this->higherHeap = new SplMinHeap();
if (count($numbers)) {
$this->insertArray($numbers);
}
}
public function insertArray ($numbers) {
foreach($numbers as $number) {
$this->insert($number);
}
}
public function insert($number)
{
$this->numbers[] = $number;
if ($this->lowerHeap->count() == 0 || $number < $this->lowerHeap->top()) {
$this->lowerHeap->insert($number);
} else {
$this->higherHeap->insert($number);
}
$this->balance();
}
protected function balance()
{
$biggerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->lowerHeap : $this->higherHeap;
$smallerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->higherHeap : $this->lowerHeap;
if ($biggerHeap->count() - $smallerHeap->count() >= 2) {
$smallerHeap->insert($biggerHeap->extract());
}
}
public function getMedian()
{
if (!count($this->numbers)) {
return null;
}
$biggerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->lowerHeap : $this->higherHeap;
$smallerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->higherHeap : $this->lowerHeap;
if ($biggerHeap->count() == $smallerHeap->count()) {
return ($biggerHeap->top() + $smallerHeap->top())/2;
} else {
return $biggerHeap->top();
}
}
}
And then the code to benchmark:
$array = [];
for($i=0; $i<100000; $i++) {
$array[] = mt_rand(1,100000) / mt_rand(1,10000);
}
$t = microtime(true);
echo array_median($array);
echo PHP_EOL . 'Sort Median: ' . (microtime(true) - $t) . ' seconds';
echo PHP_EOL;
$t = microtime(true);
$list = new MedianHeap($array);
echo $list->getMedian();
echo PHP_EOL . 'Heap Median: '. (microtime(true) - $t) . ' seconds';
Is there something in PHP that makes using heaps for this inefficient somehow or is there something wrong with my implemenation?
Is there any way I could rewrite this function with an array instead of all these if statements? Could i maybe use some for loop together with an array? How would that look like? Any suggestions of simpler code?
Here is my php function:
function to_next_level($point) {
/*
**********************************************************************
*
* This function check how much points user has achievents and how much procent it is until next level
*
**********************************************************************
*/
$firstlevel = "3000";
$secondlevel = "7000";
$thirdlevel = "15000";
$forthlevel = "28000";
$fifthlevel = "45000";
$sixthlevel = "80000";
if($point <= $firstlevel) {
$total = ($point/$firstlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $secondlevel) {
$total = ($point/$secondlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $thirdlevel) {
$total = ($point/$thirdlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $forthlevel) {
$total = ($point/$forthlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $fifthlevel) {
$total = ($point/$fifthlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
} elseif ($point <= $sixthlevel) {
$total = ($point/$sixthlevel) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
}
}
Try this:
function to_next_level($point) {
/*
**********************************************************************
*
* This function check how much points user has achievents and how much procent it is until next level
*
**********************************************************************
*/
$levelArray = array(3000, 7000, 15000, 28000, 45000, 80000);
foreach ($levelArray as $level)
{
if ($point <= $level) {
$total = ($point/$level) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
}
}
}
Start using OOP programming style. This is the perfect opportunity since it is a task without much complexity. Create a class that acts as central authority. That class can receive more methods over time. That way your code stays easy to maintain since all those functions are kept inside a class.
<?php
class levelAuthority
{
public static $thresholds = [ 3000, 7000, 15000, 28000, 45000, 80000 ];
public static function getDistanceToNextlevel($points)
{
foreach (self::$thresholds as $threshold) {
if ($points <= $threshold) {
$total = ($points/$threshold) * 100;
$remaining = round($total);
return $remaining;
}
}
}
}
// in the calling scope:
$points = 5000;
echo levelAuthority::getDistanceToNextlevel($points);
lots of answers to this!!
here is mine using a while loop - single exit point outside the loop:
function to_next_level($point) {
/*
**********************************************************************
*
* This function check how much points user has achievements and how much percent it is until next level
*
**********************************************************************
*/
$arr_level = array(3000,15000,28000,45000,80000);
$remaining = false;
while (!$remaining and list($key,$level) = each($arr_level)) {
if ($point <= $level) {
$total = ($point/$level) * 100;
$remaining = round($total);
}
}
// will return false if $point is greater than highest value in $arr_level
return $remaining;
}
You could write an additional function, that does the calculations and trigger it from the if/else if/else blocks.
function calculate_remaining($points, $level) {
$total = ($point/$level) * 100;
$remaining = round($total);
return $remaining;
}
You'd trigger this like:
if($point <= $firstlevel) {
return $calculate_remaining($point, $firstlevel);
} elseif ($point <= $secondlevel) {
return $calculate_remaining($point, $secondlevel);
} etc.
What about something like this?
function to_next_level($point)
{
$levels = array(
3000,
7000,
15000,
28000,
45000,
80000
);
foreach ($levels as $level)
{
if ($point <= $level)
{
$total = ($point / $level) * 100;
$remaining = round($total);
//echo number_format($remaining, 0, '.', ' ');
return $remaining;
}
}
}
The point levels are in order in the array, so [0] is $firstlevel, and so on. You simply iterate through the array and return whenever we reach the condition where $point is <= to the the $level.
Also, since $levels is static, it can be defined outside of the function.
simple:
<?php
$point = 100;
$remaining = 0;
$data = [
'firstlevel' => 3000,
'secondlevel' => 7000,
'thirdlevel' => 15000,
'forthlevel' => 28000,
'fifthlevel' => 45000,
'sixthlevel' => 80000
];
foreach($data as $item)
{
if($point <= $item)
{
$remaining = round(($point / $item ) * 100); //or return val
}
}
How about putting your variable into array and loop it?
function to_next_level($point) {
$data[0] = "3000";
$data[1] = "7000";
$data[2] = "15000";
$data[3] = "28000";
$data[4] = "45000";
$data[5] = "80000";
foreach ($data as $key => $value) {
if($point <= $value) {
$total = ($point/$value) * 100;
$remaining = round($total);
return $remaining;
}
}
}
I haven't try it. But it might work for you.
I have an example code. What it does is visiting pages. I want to make timeout for thread execution and shut it down when it hangs too long. I thought that there is built-in methods to implement that. Also, i've tried to do it by my own with time() function. But there is another problem. At this point $workers[$i]->kill(); script hangs and kill() method returns false so i can't shutdown thread by force. What is happening and what am i doing wrong?
Thank you!
<?php
/**
* Author: Abu Ashraf Masnun
* URL: http://masnun.me
*/
//define("TMT",3);
class WorkerThreads extends Thread
{
private $workerId;
public function __construct($string)
{
$this->command_string = trim($string);
}
public function run()
{
echo $this->command_string." ".Thread::getCurrentThreadId()."\n";
//sleep(rand(0, 3));
$str = "C:\\Users\\Alex\\Desktop\\2web\\phantom\\phantomjs.exe C:\\Users\\Alex\\Desktop\\2web\\test.js ";
$url = $this->command_string;
$d = explode("://",$url);
$ex_str = $str." ".$url." > ".$d[1].".html";
//$ex_str = $str." ".$url;
//echo $ex_str;
//$ex_str = escapeshellarg($ex_str);
//echo $ex_str;
exec($ex_str, $out);
//print_r($out);
}
}
//$data = file('sites.txt');
$data_f = file('sites_x.txt');
print_r($data_f);
$data = array();
$data_size = count($data_f);
for($i = 0;$i<$data_size;$i++)
{
$info = explode(";",trim($data_f[$i]));
if($info[1] === 'y')
continue;
$data[] = $info[0];
}
print_r($data);
$data_size = count($data);
// Worker pool
$workers = [];
$t_count = 4;
$flag = 1;
$k = 0;
//echo "$data_size";
while($flag === 1)
{
/*
//echo "$k\n";
if($k >= $data_size)
{
//echo "111"; exit();
$flag = 0;
break 2;
}
*/
$c_w = count($workers);
if($c_w < $t_count)
{
for($i = $c_w; $i<$t_count - $c_w;$i++)
{
if($k >= $data_size)
{
$flag = 0;
break;
}
$workers[$i] = new WorkerThreads($data[$k]);
//echo $data[$k]."\n";
echo "worker $i started\n";
$workers[$i]->start();
$k++;
}
}
$c_w = count($workers);
for($i=0;$i<$c_w;$i++)
{
$workers[$i]->kill();
unset($workers[$i]);
echo "unset $i\n";
//var_dump($workers[$i]->isTerminated(), $workers[$i]->getTerminationInfo());
/*
if($workers[$i]->join())
{
//var_dump($workers[$i]->isTerminated(), $my->getTerminationInfo());
echo "joining $i\n";
unset($workers[$i]);
}
*/
}
}
?>
I ran into this problem today with pthreads 2.0.10.
After recompiling PHP from source to get ZTS support, I tried building pthreads (phpize, configure, make). Everything seemed OK until I ran make test. killed-info test failed after a 30 second timeout.
Solution for me was to compile the latest pthreads from the master branch on github.
A 500 error has occurred - executing long loop with PHP.
I am currently working on a scheduling system to schedule nurses on a hospital ward, I am using a genetic algorithm to carry this out.
so I randomly allocate each nurses to a shift.
and then work out how fit they are for the shift.
I then kill off any allocation which do not meet my fitness level.
I then randomly allocate a new timetable.
Assess that for fitness
kill off any allocation which do not meet my fitness level.
Merge the two timetables, keeping the fitness allocations
I loop through generating random timetable, accessing its fitness and merging the timetables
This works fine while looping through 30 - 100 times
Once I go past the 100 mark it sometimes fails - a 500 error has occurred
This always occurs when it takes over 2:30mins to complete the script
So I'm making the assumption at some point my server times out for taking too long?
I have added <?php set_time_limit(3600);
This is at the top of my file, not inside the constructor, or the class. Is it in the right place?
it still times out at 2 and a half minute,
Here is my code, the loop is the 200 loop
Still need to refractor my code so don't be too judgmental
<?php
set_time_limit(3600);
* Description of scheduler
*
* #author Dela
*/
include ("randomTtAllocation.php");
include ("fittness.php");
class scheduler {
private $randomTimetable;
private $timetable;
private $weight;
private $newTimetable ;
private $newWeight;
function __construct($labs,$students) {
echo "helloworld";
// create random timetable and print it
$r = new randomTtAllocation();
$this->randomTimetable = $r->__randomAllocation($labs, $students);
//echo "<br>" . " ............initial Time Table............." . "<br>" ;
echo "<br>";
echo "<br>";
echo "<br>";
$this->__printTt($this->randomTimetable, $this->randomTimetable);
// work out fittness for the timetable, return fit results and print
$fit = new fittness( $this->randomTimetable, $labs, $students , $r->__getNumOfSessions());
$this->newWeight = $fit->__getnewWeight();
$this->newTimetable = $fit->__getnewTimetable();;
//echo "<br>" . " ............newTimetable.........newWeight...." . "<br>" ;
//$this->__printTt($this->newTimetable, $this->newWeight );
// sort
$this->__sortTtByWeight();
$this->timetable = $this->newTimetable;
$this->weight = $this->newWeight;
for ($i = 0; $i < 200; $i++) {
// create second time table
$this->randomTimetable = $r->__randomAllocation($labs, $students);
// echo "<br>" . " ............initial Time Table............." . "<br>" ;
// $this->__printTt($this->randomTimetable, $this->randomTimetable);
// work out fittness for the timetable, return fit results and print
$fit = new fittness( $this->randomTimetable, $labs, $students , $r->__getNumOfSessions());
$this->newWeight = $fit->__getnewWeight();
$this->newTimetable = $fit->__getnewTimetable();
//echo "<br>" . " ............tempTimetable.........tempWeight...." . "<br>" ;
//$this->__printTt($this->newTimetable, $this->timetable );
$this->__sortTtByWeight();
// merge timetables
echo "<br>" . " ......old...........new." . "<br>" ;
$this->__printTt($this->timetable,$this->newTimetable );
$this->__mergeTimetables($this->newTimetable, $this->newWeight );
//echo "<br>" . " ........... mergedTimetable.........newWeight...." . "<br>" ;
//$this->__printTt($this->timetable,$this->weight );
// fittness of new timetable
$fit = new fittness( $this->timetable, $labs, $students , $r->__getNumOfSessions());
echo "<br>" . " ......merged.......kulled" . "<br>" ;
$this->__printTt($this->timetable,$fit->__getnewTimetable() );
$this->weight = $fit->__getnewWeight();
$this->timetable = $fit->__getnewTimetable();
$c[$i] = $this->__countSlotsAllocated();
echo "<br> ". $i;
}
print_r($c);
}
// sorts the re allocated time table by weight
function __sortTtByWeight() {
// for each slot
foreach($this->newTimetable as $l => $i_value) {
$size = 0;
// see how many sessions they are taking
while ($this->newTimetable[$l][$size] != "null") {
if ($this->newTimetable[$l][$size] == "0") {
break;
}
$size++;
}
for ($i = 1; $i < $size; $i++) {
$key = $this->newWeight[$l][$i];
$key1 = $this->newTimetable[$l][$i];
$k = $i - 1;
while ($k >= 0 && $this->newWeight[$l][$k] < $key) {
$this->newWeight[$l][$k + 1] = $this->newWeight[$l][$k];
$this->newTimetable[$l][$k + 1] = $this->newTimetable[$l][$k];
$k--;
}
$this->newTimetable[$l][$k + 1] = $key1;
$this->newWeight[$l][$k + 1] = $key;
}
}
}
function __countSlotsAllocated() {
$count = 0;
foreach($this->timetable as $i => $x_value) {
$j = 0;
while (($this->timetable[$i][$j] != "null") && ($this->timetable[$i][$j] != "0")){
$count++;
$j++;
}
}
echo "count " . $count;
return $count;
}
function __mergeTimetables($tempTimeTable,$tempWeight) {
// for each session
foreach($this->newTimetable as $i => $i_value) {
$j = 0;
$k = 0;
// while there are still students
while (($tempTimeTable[$i][$j] != "null") && ($tempTimeTable[$i][$j] != "0")) {
//echo $tempTimeTable[$i][$j];
// System.out.println(timeTable[i][k]);
// see if there is a free gap
while ($this->timetable[$i][$k] != "null") {
// if student is already taking that session
if ($tempTimeTable[$i][$j] == $this->timetable[$i][$k]) {
break;
}
if ($this->timetable[$i][$k] == "0") {
$this->timetable[$i][$k] = $tempTimeTable[$i][$j];
$this->weight[$i][$k] = $tempWeight[$i][$j];
break;
}
$k++;
}
if ($this->timetable[$i][$k] == "null") {
if ($tempWeight[$i][$j] < $this->weight[$i][0]) {
$this->timetable[$i][0] = $tempTimeTable[$i][$j];
$this->weight[$i][0] = $tempWeight[$i][$j];
}
}
$j++;
}
}
}
function __returnTimetable() {
return $this->timetable;
}
function __printTt($timetable, $weight) {
foreach($timetable as $x => $x_value) {
for ($i = 0; $i < 5; $i++) {
echo $timetable[$x][$i] . " ";
}
echo " . . . . .";
for ($i = 0; $i < 5; $i++) {
echo $weight[$x][$i] . " ";
}
echo "<br>";
}
}
}
Normally you shouldn't do all this work within the http request. Instead you should start a background task and have the web page show progress on the job.
The php configuration has a time limit per request which you can adjust, but it's not expected by users to take so long.