User:Mafs/Computer algebra: Difference between revisions

From Meta, a Wikimedia project coordination wiki
Content deleted Content added
Aamorim (talk | contribs)
No edit summary
m →‎top: Not going to export random people's userspace code dumps.
 
(8 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{MoveToMediaWikiRejected}}
==Installation==
==Installation==


Line 6: Line 7:
* within the scipt adapt the path to the maxima executable
* within the scipt adapt the path to the maxima executable
* add the line
* add the line
<syntaxhighlight lang="php">
require_once("extension/Maxima.php");
require_once("extension/Maxima.php");
</syntaxhighlight>
: to your LocalSettings.php
: to your LocalSettings.php


Line 69: Line 72:
;Patch avoiding the use of $wgOut->parse() that spoils other math tags that may exist on the same page.
;Patch avoiding the use of $wgOut->parse() that spoils other math tags that may exist on the same page.
Since the parse() function can not be invoked twice on the same page, change on the code bellow
Since the parse() function can not be invoked twice on the same page, change on the code bellow
<syntaxhighlight lang="php">
<nowiki>$tex_math = "$indent<math>".$m[1]."</math>\n"</nowiki>
$tex_math = "$indent<math>".$m[1]."</math>\n"
</syntaxhighlight>
by
by
<syntaxhighlight lang="php">
<nowiki>$tex_math = $indent.MathRenderer::renderMath($m[1])."\n";</nowiki>
$tex_math = $indent.MathRenderer::renderMath($m[1])."\n";
and remove
</syntaxhighlight>
<nowiki>$text = $wgOut->parse($text);</nowiki>
and remove
<syntaxhighlight lang="php">
$text = $wgOut->parse($text);
</syntaxhighlight>
replacing the parse() function by the explicit <nowiki><math></nowiki> parsing.
replacing the parse() function by the explicit <nowiki><math></nowiki> parsing.

;Patch correcting the error return if multiple Algebra environments exist on the same page.
Since the variable <nowiki>$maxima_session_result </nowiki> is global, its value is kept within different Algebra blocks in the same page. If must be rest to false for each block. Change

<syntaxhighlight lang="php">
$maxima_input = implode(" ", $list);
$maxima_response = maxima_process($maxima_input);
</syntaxhighlight>

by

<syntaxhighlight lang="php">
$maxima_input = implode(" ", $list);
$maxima_session_result=false;
$maxima_response = maxima_process($maxima_input);
</syntaxhighlight>

;Patch correcting the bug filters out the whole output of maxima.

Change
<syntaxhighlight lang="php">
$maxima_response = preg_replace("|.*$unique_md5.in\s*\n(.*?)|s", "\\1", $maxima_response);
</syntaxhighlight>
to
<syntaxhighlight lang="php">
$maxima_response = preg_replace("|^.*?$unique_md5.in\s*\n(.*?)|s", "\\1", $maxima_response);
</syntaxhighlight>




Line 80: Line 119:




<syntaxhighlight lang="php">
<pre><nowiki>
<?php
<?php
/*
/*
Line 130: Line 169:
// Extract the maxima expressions and replace them by placehoders.
// Extract the maxima expressions and replace them by placehoders.
$i = 0;
$i = 0;
while(preg_match("|^(.*?;)\s*$|m", $text, $t)) {
while(preg_match("|^(.*?([;$]))\s*$|m", $text, $t)) {
if($t[2] == ';') {
$list[] = $t[1]." tex(%);";
$list[] = $t[1]." tex(%);";
$text = str_replace($t[0], "algebra_".md5($i), $text);
$text = str_replace($t[0], "algebra_".md5($i), $text);
$i++;
$i++;
} else {
$list[] = $t[1];
$text = str_replace($t[0], "", $text);
}
}
}



$maxima_input = implode(" ", $list);
$maxima_input = implode(" ", $list);
Line 156: Line 199:
$text = $wgOut->parse($text);
$text = $wgOut->parse($text);
} else {
} else {
$text = "<h2>&lt;Algebra&gt;</h2><h3>Maximas error message or question:</h3><pre>$maxima_response</pre><h2>&lt;/Algebra&gt;</h2>";
$text = "<h2>&lt;Algebra&gt;</h2><h3>Maximas error message or question:</h3><pre>$maxima_response</"."pre><h2>&lt;/Algebra&gt;</h2>";
}
}


Line 283: Line 326:
}
}
?>
?>
</syntaxhighlight>
</nowiki></pre>


__NOTOC__ __NOEDITSECTION__
__NOTOC__ __NOEDITSECTION__

Latest revision as of 20:50, 20 July 2023

 
A proposal to move this page to MediaWiki.org was rejected.

Installation

  • enable math in mediawiki
  • get a copy of the maxima software from http://maxima.sourceforge.net
  • put the php script as Maxima.php into the extension directory
  • within the scipt adapt the path to the maxima executable
  • add the line
  require_once("extension/Maxima.php");
to your LocalSettings.php
  • The script is not well tested. It is **not** recommended to use the script on a public site.
  • A quote from the maxima mailing list:
I'd be careful about using this script, or scripts like it. In particular
the variable

$maxima_blacklist

does not appear to contain the Maxima "system" command.  It appears that
an arbitrary user would be able to execute a system command, which (at a
very quick first read through) represents a rather large security hole.
  • So, although "system" has been added to the list, do only use the script for experiments on localhost! Mafs 20:30, 1 March 2006 (UTC)

Syntax

<Algebra> </Algebra> defines a maxima session. Any line terminating with a semicolon is passed to maxima for evaluation. For all other lines the wiki syntax applies.

The maxima syntax is described on http://maxima.sourceforge.net/docs.shtml.

If the maxima session terminates with an error or a question, the raw output of maxima will be displayed. For details how to avoid such questions see the maxima documentation.

Example

<Algebra>
Equation 1

 eq1: x^2 + 3*x*y + y^2 = 0;

Equation 2

 eq2: 3*x + y = 1;

Solution

 solve([eq1, eq2]);

----

Integration

f(x) := exp( sin(x)); 

integrate(f(x), x , 0, %pi);

</Algebra>

Screen shoot


PHP Script

Patch avoiding the use of $wgOut->parse() that spoils other math tags that may exist on the same page.

Since the parse() function can not be invoked twice on the same page, change on the code bellow

 $tex_math = "$indent<math>".$m[1]."</math>\n"

by

 $tex_math  = $indent.MathRenderer::renderMath($m[1])."\n";

and remove

 $text = $wgOut->parse($text);

replacing the parse() function by the explicit <math> parsing.

Patch correcting the error return if multiple Algebra environments exist on the same page.

Since the variable $maxima_session_result is global, its value is kept within different Algebra blocks in the same page. If must be rest to false for each block. Change

 $maxima_input = implode(" ", $list);
 
 $maxima_response = maxima_process($maxima_input);

by

 $maxima_input = implode(" ", $list);
 
 $maxima_session_result=false;
 
 $maxima_response = maxima_process($maxima_input);
Patch correcting the bug filters out the whole output of maxima.

Change

 $maxima_response = preg_replace("|.*$unique_md5.in\s*\n(.*?)|s", "\\1", $maxima_response);

to

 $maxima_response = preg_replace("|^.*?$unique_md5.in\s*\n(.*?)|s", "\\1", $maxima_response);


Attention: For copying click on edit and copy from the source text.


<?php
/*
Computer Algebra - Maxima - Mediawiki

M. Arndt <chmarndt at medemsand.de> (February 2006)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

*/

if( !defined( 'MEDIAWIKI' ) ) {
        die();
}

$wgExtensionCredits['other'][] = array(
        'name' => 'Algebra extension',
        'author' => 'Markus Arndt',
        'version' => 'February 2006',
        'url' => 'http://meta.wikimedia.org/wiki/User:Mafs/Computer_algebra',
	'description' => 'using http://maxima.sourceforge.net algebraic expressions are evaluated and displayed'
);

$wgExtensionFunctions[] = "wfAlgebraExtension";

function wfAlgebraExtension() {
	global $wgParser;
	$wgParser->setHook( "Algebra", "renderAlgebra" );
}

function renderAlgebra( $text ){

global $wgMathPath, $wgOut, $wgUploadDirectory, $maxima_session_result;

$list = array();

// Extract the maxima expressions and replace them by placehoders.
$i = 0;
while(preg_match("|^(.*?([;$]))\s*$|m", $text, $t)) {
        if($t[2] == ';') {   
                $list[] = $t[1]." tex(%);";
                $text = str_replace($t[0], "algebra_".md5($i), $text);
                $i++;
        } else {
                $list[] = $t[1];
                $text = str_replace($t[0], "", $text);
        }
}

$maxima_input = implode(" ", $list);

$maxima_response = maxima_process($maxima_input);

if ($maxima_session_result) {

	$maxima_response = str_replace("$$",  "--n9853g204zh--", $maxima_response);
	$maxima_response = str_replace("|\n", "--n9853g204zh--", $maxima_response);
	
	// Replace the placeholders by maximas tex expressions, add math-tags
	$i = 0;
	while(preg_match("/--n9853g204zh--(.*?)--n9853g204zh--/is", $maxima_response, $m)) { 
		$tex_math = "$indent<math>".$m[1]."</math>\n";
		$maxima_response = substr($maxima_response, 0, strpos($maxima_response, $m[0])).substr($maxima_response, strpos($maxima_response, $m[0])+strlen($m[0]));
		$text = str_replace("algebra_".md5($i), $tex_math, $text);
		$i++;
	}
	$text = $wgOut->parse($text);
} else {
	$text = "<h2>&lt;Algebra&gt;</h2><h3>Maximas error message or question:</h3><pre>$maxima_response</"."pre><h2>&lt;/Algebra&gt;</h2>";
}

return $text;
}



function maxima_process($text) {

global $maxima_process_message, $maxima_ex_time, $maxima_session_result;

// Some Settings
$maxima_path = "/usr/local/bin/maxima";
$temp_path = "/tmp/maxima/";
$max_execution_time = 5; // in seconds

// As a simplistic security measure, all lines containing one of these expressions
// are not passed to maxima.
$maxima_blacklist = array("save", "load", "plot", "lisp", "includ", "compil", "file", "batch", "stringout", "translat", "stout", "stin", "block", "system"); 

$maxima_question = false; 
$max_execution_time_exceeded = false;
$unique_md5 = md5 (uniqid (rand()));
$maxima_input = $text;
$maxima_process_message = "";

if ( ! is_dir( $temp_path ) ) { mkdir( $temp_path, 0777 ); }

$maxima_input = str_replace("\n", "", $maxima_input);
$lines = explode(";", $maxima_input);
foreach($lines as $line) {
	$delete = False;
	foreach($maxima_blacklist as $d) {
		if (eregi($d, $line, $a)) {
			$delete = True; 
			$maxima_process_message .= "The expression \"".trim($line).";\" has not been passed to maxima.<br>";
			break;
		} 
	}
	if (!$delete) $newline[] = $line; 
}
$maxima_input = implode(";", $newline);

$maxima_input = $maxima_input . " maxima_session_".$unique_md5.";";
$out_file  = $temp_path."maxima_$unique_md5.out";
$in_file   = $temp_path."maxima_$unique_md5.in";
$pid_file  = $temp_path."maxima_$unique_md5.pid";

$fp = fopen($in_file, "w");
	fwrite($fp, $maxima_input);
fclose($fp);

$cmd = "env MAXIMA_USERDIR=$temp_path $maxima_path --batch=\"$in_file\" > $out_file &\njobs -l > $pid_file";

// For checking the environment:
// $cmd = "/usr/local/bin/maxima -d";
// return $cmd;

$start_time = time() + microtime();

passthru($cmd, $ret);

// Process Control   *****************************************************************

$pf = file_get_contents($pid_file);
preg_match("/^.*? ([0-9]+) .*/", $pf, $p);
$pid = trim($p[1]);

if ($pid > 0 and is_numeric($pid)) {
	while( true ) {
	
		$delta_time = time() + microtime() - $start_time; 
		if ($delta_time > $max_execution_time) $max_execution_time_exceeded = true;

		shell_exec("kill -s stop $pid");
			$l = shell_exec("wc -l $out_file"); 
			$m = shell_exec("head -n $l $out_file");	
		shell_exec("kill -s cont $pid");

		if (preg_match("/.*\?$/s", trim($m), $a)) $maxima_question = true;
		
		$s = shell_exec("ps -o pid,args -p $pid | grep maxima");
		//return $s;
		if (!strstr($s, $pid)) break;
		
		if ($max_execution_time_exceeded or $maxima_question) break;
	}

	$s = shell_exec("ps -o pid,args -p $pid | grep maxima");
	if (strstr($s, $pid)) shell_exec("kill $pid");

// Process Control   *****************************************************************

	$end_time = time() + microtime();
	$maxima_ex_time = ($end_time - $start_time);

	if (file_exists($out_file) ) $maxima_response = file_get_contents($out_file); else {
	$maxima_process_message .= "Maxima did not run properly (1).<br>";
	}
	
	// remove repeated questions
	if ($maxima_question) {
		preg_match("/.*(\n[^\n]*?\?)$/s", trim($m), $a);
		$maxima_response = str_replace($a[1], "", $maxima_response);
		$maxima_response = trim($maxima_response)."\n\n".trim($a[1]);
	}
	
	if (strstr($maxima_response, "maxima_session_".$unique_md5)) $maxima_session_result = true;

	// remove headings, tail
	if (strstr($maxima_response, $unique_md5)) {
		$maxima_response = preg_replace("|.*$unique_md5.in\s*\n(.*?)|s", "\\1", $maxima_response);
		$maxima_response = preg_replace("|(.*?)\n[^\n]*?maxima_session_$unique_md5.*|s", "\\1", $maxima_response);
	}
	
	if ($max_execution_time_exceeded) $maxima_process_message .= "The maximal allowed execution time has been exceeded.<br>";

} else {
	$maxima_process_message .= "Maxima did not run properly (2).<br>";
}

$s = shell_exec("rm ".$temp_path."maxima_".$unique_md5."*");

return $maxima_response;
}
?>