Commits

Eike Welk committed 0b3af5b

More documentation tweaks.

Comments (0)

Files changed (5)

 This project contains a very simple, and incomplete, symbolic math library in 
 Scala. It can *differentiate* and *evaluate* simple mathematical expressions. 
 The library also contains some aspects of an internal DSL: The expressions can 
-be entered like regular math with Int or Double objects, and there is a ML 
-style *"let" expression*. Here is a short example that demonstrates the 
+be entered like regular math with ``Int`` or ``Double`` objects, and there is 
+a ML style *"let" expression*. Here is a short example that demonstrates the 
 differentiation feature::
 
     import symathm.Expression._
     import symathm.ExprOps._
-    import Expr.{int2Num, double2Num}
     
     //Create some symbols (unknown variables)
-    val (a, b, c, x) = (Sym("a"), Sym("b"), Sym("c"), Sym("x"))
+    val (a, x) = (Sym("a"), Sym("x"))
 
     //Create an expression. `~^` denotes exponentiation (power).
-    val expr1 = 2 * x~^4 + 5 * x~^2 + x~^0.5 
+    val expr1 = a * x~^4 + 5 * x~^2 + x~^0.5 
+
     //Differentiate the expression with respect to `x`
     val dexpr1 = diff(expr1, x) 
 
     //Print the expression in human readable form.
-    //Prints: "8.0 * x ~^ 3.0 + 10.0 * x + 0.5 * x ~^ -0.5;;"
+    //Prints: "4.0 * a * x ~^ 3.0 + 10.0 * x + 0.5 * x ~^ -0.5;;"
     pprintln(dexpr1)
 
-The library is not intended to be seriously used. Instead it should demonstrate 
+The library is not intended to be used seriously. Instead it should demonstrate 
 features of Scala that are interesting for programmers that come form 
 traditional object oriented languages; such as: C++, Java, Python, Ruby.
 The project should especially demonstrate the usefulness of pattern matching.
 
   scala -classpath bin/ UseTheLibraries
 
+To start Scala's read-eval-print loop, you need to specify the ``classpath`` 
+where the compiled files are found (but don't specify an object that should 
+be run)::
+
+  scala -classpath bin/ 
+
 With IDE
 --------
 
 
 * Add derivation of the ``Log`` node.
 * Add new nodes, for example ``sin``, ``cos`` and ``tan``.
-* Add new simplification algorithms. Especially add a separate ``simplify`` 
-  function.
 * Add function call node. Maybe this makes an inert ``diff`` node superfluous.
   (See point below.)
 * Add ``lambda`` (function body) node.
 * Implement an inert ``diff`` node. The "a$x" notation is a hack.
-* Implement some of the TODOs
+
+* Implement an algorithm to distribute factors over sums, and distribute 
+  powers over products. For example: ``(a + b) * c`` --> ``a*c + b*c``. 
+  
+  This is interesting for ``eval``: more operators with only numeric arguments 
+  can be found, and evaluated. 
+
+* Implement an algorithm to collect factors and powers. (The opposite of the 
+  algorithm above.) It makes formulas look good.
+* Maybe add a separate ``simplify`` function.
+* Implement some of the TODOs in the code.

src/UseTheLibraries.scala

     
     import symathm.Expression._
     import symathm.ExprOps._
-    import Expr.{int2Num, double2Num}
+//    import Expr.{int2Num, double2Num}
     
     //Create some symbols (unknown variables)
     val (a, b, c, x) = (Sym("a"), Sym("b"), Sym("c"), Sym("x"))
     
     import symathv.Expression._
     import symathv.ExprOps._
-    import Expr.{int2Num, double2Num}
     
     //Create some symbols (unknown variables)
     val (a, b, c, x) = (Sym("a"), Sym("b"), Sym("c"), Sym("x"))
     
     import symathoo.Expression._
     import symathoo.ExprOps._
-    import Expr.{int2Num, double2Num}
     
     //Create some symbols (unknown variables)
     val (a, b, c, x) = (Sym("a"), Sym("b"), Sym("c"), Sym("x"))

src/symathm/SymbolicMainM.scala

 /**
  * Simple Symbolic Algebra in Scala
  * 
- * This implementation uses '''pattern matching''',  classes contain 
- * '''only data'''. The algorithms that operate on the data are entirely separate 
- * and reside on object `AstOps`.
- *
- * A much more involved project for a miniature programming language in
- * Scala is Kiama:
- * http://code.google.com/p/kiama/wiki/Lambda2
- *
- * See also this discussion:
- * http://www.scala-lang.org/node/6860
+ * This implementation uses '''pattern matching''', and techniques from 
+ * functional programming.
+ * 
+ * A mathematical expression consists of a recursive tree of Nodes.
+ * Nodes contain '''only data''' and have '''no methods'''. The algorithms that 
+ * operate on the data (for example the differentiation algorithm) are entirely 
+ * separate, and implemented in object `ExprOps`. 
+ * 
+ * The algorithms use pattern matching to react specifically for different 
+ * kinds of nodes.
  */
 package symathm
 
     def ~^(other: Expr) = Pow(this, other)
     def :=(other: Expr) = Asg(this, other)
   }
-  object Expr {
-    //implicit conversions so that numbers can be used with the binary operators
-    implicit def int2Num(inum: Int) = Num(inum)
-    implicit def double2Num(dnum: Double) = Num(dnum)
-  }
-  
-  
+
   //The concrete node types
   /** Numbers */
   case class Num(num: Double) extends Expr
   /** Assignment: `x := a + b`. Used by `let` and `Env` convenience objects. */ 
   case class Asg(lhs: Expr, rhs: Expr) extends Expr
   
-  
+    
   /** Type of the environment, contains variables that are assigned by let. */
   type Environment = Map[String, Expr]
   val Environment = Map[String, Expr] _
   
   
   //--- Nicer syntax (the "DSL") ---------------------------------------------
+  //Implicit conversions so that numbers can be used with the binary operators
+  implicit def int2Num(inum: Int) = Num(inum)
+  implicit def double2Num(dnum: Double) = Num(dnum)
+
   /** 
    * Convenience object to create an environment from several assignments.
    * 
  * */
 object ExprOps {
   import Expression._
-  import Expr.{int2Num, double2Num}
   
   /** 
    * Convert the AST to a string in normal infix notation for math.
 object SymbolicMainM {
   import Expression._
   import ExprOps._
-  import Expr.{int2Num, double2Num} //enables `2 * x` instead of `Num(2) * x`
 
   //Create some symbols for the tests (unknown variables)
   val (a, b, x) = (Sym("a"), Sym("b"), Sym("x"))

src/symathoo/SymbolicMainOo.scala

 /**
  * Simple Symbolic Algebra in Scala
  * 
- * This implementation uses '''object oriented''' style,  classes contain 
- * '''data and methods''' that operate on the data.
+ * This implementation uses '''object oriented''' style.
+ * A mathematical expression consists of a recursive tree of Nodes.
+ * Nodes contain '''data and methods''' that operate on the data.
   */
 package symathoo
 
  * Define the expression's nodes, and the DSL.
  */
 object Expression {
+  //--- DSL aspect ------------------------------------------------------
+  //Implicit conversions so that numbers can be used with the binary operators
+  implicit def int2Num(inum: Int) = Num(inum)
+  implicit def double2Num(dnum: Double) = Num(dnum)
+
   //The elements of the AST ----------------------------------------------
   /**
    * Common base class of all expression (AST) nodes.
    * [[symathoo.Expression.Num]], and helper methods.
    */
   object Expr {
-    //implicit conversions so that numbers can be used with the binary operators
-    implicit def int2Num(inum: Int) = Num(inum)
-    implicit def double2Num(dnum: Double) = Num(dnum)
-  
     /**
      * Compute the precedence of each node, for putting parentheses around 
      * the string representation if necessary.
   
   /** Power (exponentiation) operator */
   case class Pow(base: Expr, exponent: Expr) extends Expr {
-    import Expr.{int2Num, double2Num}
-    
     /** Convert instance to a pretty printed string. */
     override def prettyStr(outerNode: Expr = Let("", 0, 0)) = {
       val sRep = base.prettyStr(this) + " ~^ " + exponent.prettyStr(this)
 object SymbolicMainOo {
   import Expression._
   import ExprOps._
-  import Expr.{int2Num, double2Num}
 
   //Create some symbols for the tests (unknown variables)
   val (a, b, x) = (Sym("a"), Sym("b"), Sym("x"))

src/symathv/SymbolicMainV.scala

 /**
  * Simple Symbolic Algebra in Scala
  * 
- * This implementation uses the '''Visitor pattern''',  classes contain 
- * '''mostly data''' with some trivial functions that call into the visitor.
+ * This implementation uses the '''Visitor pattern'''. 
+ * A mathematical expression consists of a recursive tree of Nodes. Nodes 
+ * contain '''mostly data''' and only trivial methods. 
+ * 
+ * The visitor is an object that embodies a certain algorithm, for example
+ * to compute the derivative. It has specific methods for each node type.  
+ * The nodes' trivial methods call associated methods of the visitor, 
+ * that perform the algorithm. 
+ * 
+ * The methods of the visitor parallel the cases of a `match` expression.
  */
 package symathv
 
     /** Call into visitor that computes an expression. */
     def acceptExpr(v: ExprVisitor): Expr
   }
-  object Expr {
-    //implicit conversions so that numbers can be used with the binary operators
-    implicit def int2Num(inum: Int) = Num(inum)
-    implicit def double2Num(dnum: Double) = Num(dnum)
-  }
   
   
   //The concrete node types
   
   
   //--- Nicer syntax (the "DSL") ---------------------------------------------
-  /** 
+  //Implicit conversions so that numbers can be used with the binary operators
+  implicit def int2Num(inum: Int) = Num(inum)
+  implicit def double2Num(dnum: Double) = Num(dnum)
+
+    /** 
    * Convenience object to create an environment from several assignments.
    * 
    * Usage:
 object SymbolicMainV {
   import Expression._
   import ExprOps._
-  import Expr.{int2Num, double2Num}
 
   //Create some symbols for the tests (unknown variables)
   val (a, b, x) = (Sym("a"), Sym("b"), Sym("x"))