I want to use gaussian elimination to solve the following matrix Matrix and this is the answer I'm expecting. I would like to get back an equation in the form as is displayed in answer but i can't figure out how to do it.
public function gauss($A, $x) {
# Just make a single matrix
for ($i=0; $i < count($A); $i++) {
$A[$i][] = $x[$i];
}
$n = count($A);
for ($i=0; $i < $n; $i++) {
# Search for maximum in this column
$maxEl = abs($A[$i][$i]);
$maxRow = $i;
for ($k=$i+1; $k < $n; $k++) {
if (abs($A[$k][$i]) > $maxEl) {
$maxEl = abs($A[$k][$i]);
$maxRow = $k;
}
}
# Swap maximum row with current row (column by column)
for ($k=$i; $k < $n+1; $k++) {
$tmp = $A[$maxRow][$k];
$A[$maxRow][$k] = $A[$i][$k];
$A[$i][$k] = $tmp;
}
# Make all rows below this one 0 in current column
for ($k=$i+1; $k < $n; $k++) {
$c = -$A[$k][$i]/$A[$i][$i];
for ($j=$i; $j < $n+1; $j++) {
if ($i==$j) {
$A[$k][$j] = 0;
} else {
$A[$k][$j] += $c * $A[$i][$j];
}
}
}
}
# Solve equation Ax=b for an upper triangular matrix $A
$x = array_fill(0, $n, 0);
for ($i=$n-1; $i > -1; $i--) {
$x[$i] = $A[$i][$n]/$A[$i][$i];
for ($k=$i-1; $k > -1; $k--) {
$A[$k][$n] -= $A[$k][$i] * $x[$i];
}
}
return $x;
}
I hope someone can help me to rewrite this code so it gives the solution i've provided or recommend a library which is capable of doing this.
I've searched for possible solutions on Google but haven't been able to find one yet.
Thanks in advance.
Here is my code:
$n = 300;
$set = 0;
$set2 = 0;
for($i = 1; $i<$n; $i++)
{
for($j = 1; $j <$i; $j++)
{
$qol = $i % $j;
if($qol == 0)
{
$set += $j;
}
}
for($s=1; $s<$set; $s++)
{
$qol2 = $set % $s;
if($s == 0)
{
$set2 += $s;
}
}
if($set2 == $i)
{
echo "$set and $i are amicable numbers</br>";
}
}
I do not know what the heck the problem is!
FYI: 220 and 284 are an example of amicable numbers. The sum of the proper divisors of one number are equal to other number and vice versa (wiki).
I am having troubles following your logic. In your code how would $set2 == $i ever be true? Seems to me that $i would always be greater.
I would do it the following way:
First make a separate function that finds the sums of the proper divisors:
// Function to output sum of proper divisors of $num
function sumDiv($num) {
// Return 0 if $num is 1 or less
if ($num <= 1) {
return 0;
}
$result = 1; // All nums divide by 1
$sqrt = sqrt($num);
// Add divisors to result
for ($i = 2; $i < $sqrt; $i++) {
if ($num % $i == 0) {
$result += $i + $num / $i;
}
}
// If perfect square add squareroot to result
if (floor($sqrt) == $sqrt) {
$result += $sqrt;
}
return $result;
}
Next check each iteration for a match:
$n = 1500;
for ($i = 1; $i < $n; $i++) {
// Get sum of proper devisors of $i, and sum of div. of result.
$currentDivs = sumDiv($i);
$resultDivs = sumDiv($currentDivs);
// Check for a match with sums not equal to each other.
if ($i == $resultDivs && $currentDivs != $resultDivs) {
echo "$i and $currentDivs are amicable numbers<br>";
}
}
Here a functioning phpfiddle.
Warning: Large numbers will take very long to process!
Why does this not make two arrays one within 7 numbers and one within 2 numbers in it?
It somehow combines the both into one.
When i echo $arvottuLottoRivi and $lottoLisaNumerot in my HTML page the result is:
$arvottuLottoRivi (1,2,3,4,5,6,7,8,9,10) : $lottoLisaNumerot
all the seven numbers.
I have now tried three different styles but same thing happens in all cases
// VARAIBLES
$lottoNumerot = $_POST["lottoNumerot"];
$mahdollisetNumerot = array("1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39");
$i = 0;
$l = 0;
$k = 0;
//ARRAYS
$arvottuLottoRivi = array();
$lottoLisaNumerot = array();
$tenNumbersArray = array();
//FUNCTIONS
$numeroidenRandomointi = array_rand($mahdollisetNumerot, 10);
// COUNTS ARRAY LENGHT
$lottoRivinPituus = count($numeroidenRandomointi);;
// LOOPS
foreach($numeroidenRandomointi as $randomNumero){
while($i <= $lottoRivinPituus){
$i++;
}
$randomToArray = array_push($tenNumbersArray, $randomNumero);
}
// LOOPIT
foreach($tenNumbersArray as $randomToSite){
while($l <= $lottoRivinPituus){
$l++;
}
if($l <= 7){
array_push($arvottuLottoRivi, $randomToSite);
}
}
foreach($tenNumbersArray as $randomToSiteLisanuimerot){
while($k <= $lottoRivinPituus){
$k++;
}
if($k >= 7){
array_push($lottoLisaNumerot, $randomToSiteLisanuimerot);
}
}
$arvottuLottoRivi = implode(' ', $arvottuLottoRivi);
$lottoLisaNumerot = implode(' ', $lottoLisaNumerot);
When you write:
foreach($tenNumbersArray as $randomToSiteLisanuimerot){
while($k <= $lottoRivinPituus){
$k++;
}
if($k >= 7){
array_push($lottoLisaNumerot, $randomToSiteLisanuimerot);
}
}
the while loop is equivalent to:
$k = $lottoRivinPituus + 1;
Since $lottoRivinPituus is 10, $k is always 11. Therefore, if($k >= 7) is always true, so all elements of $randomToSiteLisanuumerot are copied to $lottoLisaNumerot. Similarly, in the previous loop, the test if ($l <= 7) is always false, so nothing is copied to $arvottuLottoRivi.
I think you were trying to test the current position in the loop, not the count of all elements in the array. You can do it like this:
foreach($tenNumbersArray as $l => $randomToSite){
if($l < 7){
array_push($arvottuLottoRivi, $randomToSite);
}
}
foreach($tenNumbersArray as $k => $randomToSiteLisanuimerot){
if($k >= 7){
array_push($lottoLisaNumerot, $randomToSiteLisanuimerot);
}
}
But this wastes time iterating over elements it doesn't care about. A better way would be:
$arvotSize = min(7, $lottoRivinPituus);
for ($l = 0; $l < $arvotSize; $l++) {
array_push($arvottuLottoRivi, $tenNumbersArray[$l]);
}
for ($k = $arvotSize; $k < $lottoRivinPituus; $k++) {
array_push($lottoLisaNumerot, $tenNumbersArray[$k]);
}
I really didn't get your code.
Why don't use rand function?
$randomNumbers1 = array();
$randomNumbers2 = array();
$i = 0;
while ($i < 7) {
$aNumber = rand(1, 39);
if (!in_array($aNumber, $randomNumbers1)) {
$randomNumbers1[] = $aNumber;
$i++;
}
}
$i = 0;
while ($i < 2) {
$aNumber = rand(1, 39);
if (!in_array($aNumber, $randomNumbers2)) {
$randomNumbers2[] = $aNumber;
$i++;
}
}
And if the seconds array cannot contains any number within the first one:
$i = 0;
while ($i < 2) {
$aNumber = rand(1, 39);
if (!in_array($aNumber, $randomNumbers2) && !in_array($aNumber, $randomNumbers1)) {
$randomNumbers2[] = $aNumber;
$i++;
}
}
I'm trying to align strings in PHP using Levenshtein distance algorithm. The problem is that my back tracing code does not work properly for all cases. For example when the second array has inserted lines at the beginning. Then the back tracing will only go as far as when i=0.
How to properly implement back tracing for Levenshtein distance?
Levenshtein distance, $s and $t are arrays of strings (rows)
function match_rows($s, $t)
{
$m = count($s);
$n = count($t);
for($i = 0; $i <= $m; $i++) $d[$i][0] = $i;
for($j = 0; $j <= $n; $j++) $d[0][$j] = $j;
for($i = 1; $i <= $m; $i++)
{
for($j = 1; $j <= $n; $j++)
{
if($s[$i-1] == $t[$j-1])
{
$d[$i][$j] = $d[$i-1][$j-1];
}
else
{
$d[$i][$j] = min($d[$i-1][$j], $d[$i][$j-1], $d[$i-1][$j-1]) + 1;
}
}
}
// backtrace
$i = $m;
$j = $n;
while($i > 0 && $j > 0)
{
$min = min($d[$i-1][$j], $d[$i][$j-1], $d[$i-1][$j-1]);
switch($min)
{
// equal or substitution
case($d[$i-1][$j-1]):
if($d[$i][$j] != $d[$i-1][$j-1])
{
// substitution
$sub['i'][] = $i;
$sub['j'][] = $j;
}
$i = $i - 1;
$j = $j - 1;
break;
// insertion
case($d[$i][$j-1]):
$ins[] = $j;
$j = $j - 1;
break;
// deletion
case($d[$i-1][$j]):
$del[] = $i;
$i = $i - 1;
break;
}
}
This is not to be nit-picky, but to help you find the answers you want (and improve your implementation).
The algorithm you are using is the Wagner-Fischer algorithm, not the Levenshtein algorithm. Also, Levenshtein distance is not use to align strings. It is strictly a distance measurement.
There are two types of alignment: global and local. Global alignment is used to minimize the distance between two entire strings. Example: global align "RACE" on "REACH", you get "RxACx". The x's are gaps.
In general, this is the Needleman-Wunsch algorithm, which is very similar to the Wagner-Fischer algorithm. Local alignment finds a substring in a long string and minimizes the difference between a short string and a the substring of the long string.
Example: local align "BELL" on "UMBRELLA" and you get "BxELL" aligned on "BRELL". It is the Smith-Waterman algorithm which, again, is very similar to the Wagner-Fischer algorithm.
I hope that this is helpful in allowing you to better define the exact kind of alignment you want.
I think your bug is exactly what you say in your question that it is: you stop as soon as i==0, instead of going all the way to i==0 && j==0. Simply replace this condition:
while($i > 0 && $j > 0)
with
while ($i > 0 || $j > 0)
and you're halfway to your solution. The tricky bit is that if $i==0, then it's incorrect to use the array index $i-1 in the loop body. So you'll also have to change the body of the loop to something more like
while ($i || $j) {
$min = $d[$i][$j]; // or INT_MAX or something
if ($i && $j && $min > $d[$i-1][$j-1]) {
$newi = $i-1;
$newj = $j-1;
$min = $d[$newi][$newj];
}
if ($i && $min > $d[$i-1][$j]) {
$newi = $i-1;
$newj = $j;
$min = $d[$newi][$newj];
}
if ($j && $min > $d[$i][$j-1]) {
$newi = $i;
$newj = $j-1;
$min = $d[$newi][$newj];
}
// What sort of transformation is this?
if ($newi == $i && $newj == $j) {
assert(false); // should never happen
} else if ($newi == $i) {
// insertion
$ins[] = $j;
} else if ($newj == $j) {
// deletion
$del[] = $i;
} else if ($d[$i][$j] != $d[$newi][$newj]) {
// substitution
$sub['i'][] = $i;
$sub['j'][] = $j;
} else {
// identity
}
assert($newi >= 0); assert($newj >= 0);
$i = $newi;
$j = $newj;
}
I have this piece of code that loops 1 through 99 and is a formula.
function getExperienceByLevel ($maxLevel)
{
$levels = array ();
$current = 0;
for ($i = 1; $i <= $maxLevel; $i++)
{
$levels[$i - 1] = floor ($current / 4);
$current += floor($i+300*pow(2, ($i/9.75)));
}
return $levels;
}
First you initiate it like so $aLevels = getExperienceByLevel(99); then to see how much EXP you need to get to level 6 you do this echo $aLevels[5]; since it's an array.
Now I'm trying to do reverse. Get Level by EXP.
function getLevelByExp($exp)
{
$myLevel = 0;
$aLevels = getExperienceByLevel(99);
for ($i = 1; $i < 100; $i++)
{
if ($exp > $aLevels[$i-1])
{
return $myLevel;
}
}
}
When called upon getLevelByExp(1124); or any number inside, it seems to return a zero. But it seems to work when you put echos inside that statement.
Like instead of return $myLevel do echo "You are up to level $i<br />"; and it will go all the way up to the current level you've gained EXP for.
But still.. doesn't work when I want to simply return a number.
This seems to work better than your function:
function getLevelByExp($exp)
{
$aLevels = getExperienceByLevel(99);
for ($i = 0; $i <= 99; ++$i)
{
//echo "cmp $exp >= aLevels[$i]={$aLevels[$i]}\n";
if ($exp <= $aLevels[$i])
return $i - 1;
}
return -1;
}
It needs improvement for the edge cases, such as when $exp is zero.
Return $i instead because it always '0'
if ($exp > $aLevels[$i-1]) {
return $i;
}
You never change $myLevel, so it will always stay at 0.
Try returning $i instead of $myLevel, as $i is actually changing:
function getLevelByExp($exp) {
$aLevels = getExperienceByLevel(99);
for ($i = 1; $i < 100; $i++) {
if ($exp > $aLevels[$i-1]) {
return $i;
}
}
}