User:Mafs/Computer algebra: Difference between revisions

From Meta, a Wikimedia project coordination wiki
Content deleted Content added
Aamorim (talk | contribs)
No edit summary
Aamorim (talk | contribs)
No edit summary
Line 67: Line 67:
==PHP Script==
==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
Since the parse() function can not be invoked twice on the same page, change on the code bellow
<nowiki>$tex_math = "$indent<math>".$m[1]."</math>\n"</nowiki>
<nowiki>$tex_math = "$indent<math>".$m[1]."</math>\n"</nowiki>

Revision as of 01:53, 28 October 2006

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.


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


<nowiki>
<?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)) { 
	$list[] = $t[1]." tex(%);";
	$text = str_replace($t[0], "algebra_".md5($i), $text);
	$i++;
}


$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><Algebra></h2><h3>Maximas error message or question:</h3><pre>$maxima_response

</Algebra>

";

}

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.
"; 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).
"; }

// 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.
";

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

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

return $maxima_response; } ?>

</nowiki>