User:Mafs/Computer algebra

From Meta, a Wikimedia project coordination wiki
A proposal to move this page to was rejected.


  • enable math in mediawiki
  • get a copy of the maxima software from
  • put the php script as Maxima.php into the extension directory
  • within the scipt adapt the path to the maxima executable
  • add the line
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


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)


<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

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.


Equation 1

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

Equation 2

 eq2: 3*x + y = 1;


 solve([eq1, eq2]);



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

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


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"


 $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);


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


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


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

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

Computer Algebra - Maxima - Mediawiki

M. Arndt <chmarndt at> (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
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' ) ) {

$wgExtensionCredits['other'][] = array(
        'name' => 'Algebra extension',
        'author' => 'Markus Arndt',
        'version' => 'February 2006',
        'url' => '',
	'description' => 'using 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);
        } 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);
	$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>";
	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_$";
$pid_file  = $temp_path."maxima_$";

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

$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("|.*$\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;