Maplesoft Blog

The Maplesoft blog contains posts coming from the heart of Maplesoft. Find out what is coming next in the world of Maple, and get the best tips and tricks from the Maple experts.

Hello MaplePrime users,

Yesterday, I posted my MagicPuzzles package to the MapleCloud. It is a collection of tools I have written for manipulating, solving, and visualizing puzzles like Magic Squares and Magic Stars. Here's a sample solution for each:



For the Magic Square, the numbers on each horizontal and vertical line, along with the numbers on each of the two diagonals, add up to 65.

The inaugural version has separate sub-packages for:

  • Magic Annulai (my own name)
  • Magic Hexagons
  • Magic Squares
  • Magic Stars

Moreover, each sub-package contains these commands:

  • Equations(), to return the linear equations for the variables based on the Magic Sum;
  • Constraints(), to return the conditions that prevent redundant solutions found by reflections and rotations;
  • VerifySolution(), to confirm if a list of numbers is a solution;
  • EquivalentSolutions(), to determine solutions equivalent to a given solution;
  • PrimarySolution(), which takes a solution and returns the associated primary solution;
  • Reflection() and Rotation(), to reflect and rotate a solution; and
  • Draw(), to provide a visualization (like the ones above).

There is also a command, MagicSolve(), which is used to find solutions, which take the form of permutations of [1,...n] for some positive integer n, to the equations. Essentially, it solves the linear equations, and cycles through all permutations for the free variables, and selects those that give "magic" solutions.

In future versions, I intend to add:

  • Other specific classes of problems;
  • More sample solutions; and
  • Known algorithms for finding particular solutions.


To install the package, you can do so from here, or just execute the following within Maple 2017+:

PackageTools:-Install( 5755630338965504, 'overwrite' );

There are many examples in the help pages.

I think others will find this package interesting and useful, and I encourage you to check it out.

This is the final installment in a series of three articles outlining new features of Maple's command line (TTY) interface. Today we'll cover improvements to ImageTools:-Preview for use from a terminal.

Character based terminals are not well suited for displaying graphics, although the earliest Maple plotting support was specifically for such devices because better options were not widely available. But for text-based work such as writing code and documentation, many developers still prefer to work in a terminal, where everything is just a keystroke or two away. A problem arises when working on projects involving graphics. Obviously, it's easy to open an appropriate image viewer for such tasks, but for quick previews where details aren't important, a terminal-based solution can be convenient.

As a sample image for the first few examples, we'll use this well known public domain test image, commonly referred to as the baboon, although it is actually a mandrill:

The ImageTools:-Preview function has always been able to render output in a terminal. The output is akin to what one might have seen hanging on a data center wall in the 1970s:

> interface(screenheight=40,screenwidth=72,plotdevice=char):
> with(ImageTools):
> img := Read("../../Pictures/baboon.png");
                     [ 1..512 x 1..512 x 1..3 3-D Array ]
              img := [ Data Type: float[8]              ]
                     [ Storage: rectangular             ]
                     [ Order: C_order                   ]

> Preview(img);
oO*O*o++==**+o+=+-+=*o**=++=+*++++o*++~=o===*****==+===+++--~~=~~~+*
@o*++++~=+~++++++=++**oO*oOOooOOOOOOoo*++ooo*+++====+*++====~~~-==+*
Ooo++===+==+***o*oo***oooOo*++==**==~~=*oO****ooooooooo***++=~~~~~+*
@o*+=+~===*+oOo@@@@@@@@@@@@@@oooOOO*oO@@OOO@@@@@@@@@@@@@o*+===~-=++*
O**==~+=~=+*O@O@@@@@@OO@@O@@@@@@@OOO@@o*o@+=**=+@ooOOOoo+=+==~~~~=++
o++++=-~~~=++*oOO**O@*=**+o@Oo@@@@@@@o*O@@o===+*@+~+o*+++~===~~=~++*
+*++==~~==~=+=++*+=o@@@@@@@@ooo@@@@OO*Ooo@@@@OO*+=*oo*+==~~~~--=~++o
o*+=+~=~~=~~++++*****oo*+**=+O@OOO*o+*oo+++*+=~+*oo**+*+~=~~-~~~~=+=
O*=*=~=~~===~==+****OOOooooOOOO+O*=+*+Oo=~-~~=OOo**+*++=~~~-~-~-~+=+
O+++~~+~=~~+==+o**oo@@*~-----O*=@o++=o@=   -~~=*ooo*o+====~~~~-~~+=+
*o**++===+~=+=*+OOOOo=-~~   -o*=o*=++=o     -~==+oo**o++~~~----~~~++
o*oo*===+==+=*oo*oO=-=-  -  -*=+o+=++=+    -----=**+++*+~~==~-~-=+~*
*o**+*=++=~==~=+**O~- ~     -+=+*+=++==       ~~-~++=+~=~~~~-~~~+==+
ooo*o***+++~+==+oo==-  -    -+=++=+++==      -- -~+=+~~~~~~~=~~===+*
oo*o*==*+=====oooo-~-  -    -==*+==++==         --~*++=~=--~-=====**
*oooo*+*+===++=*@*--~-      ~=+*+==++==         ~--+*==+=~~~-=~+++**
oOOoOo**+*+=+=+O@=- ~-      ~=+*+~~=++~        -- -*o*+====~=+=+*++*
++*ooooOo+**+*OoO~~ -~      ~=+*+-~+++~-      -~  ~ooo+=~=~=+=******
*o+OO@@ooOooO@O@@~=- --     ==++=~~+++~       ~  -+Oo*==++=*+**+***+
*++*ooOOOO@OOO@@@=-=- -     =+++=-~+++~      ~   -*o***++=++*o*oo*oo
~===++**oOOO@@@@@@-~-  -    ~***=- =++-     -   -~oOo**o*oooo***oooo
~~~=~~==+O@@@@@@@@=-=  -  - -++*=-~=++     --   ~+@OO*******o**o*OOO
=~-~-=+oO@@@@@@@@@*~--  -    =+*+==+*~  -  -   -~O@@o*ooo*ooooooooOO
----~==+o@@@@@@@@@o+-~  -  - ~**+=++*- -  -- ---=@@@OO**oooooo*ooooo
-~~~~=+**o@@@@@@@@@+~~~-=- --=**+==++- ~  + -~~~*OOOOoo*ooooo***oOOO
---~====*@@@@@@@@@@O+~+=~= -~+*++=+++-~- =+~~~++*oOOOOoooooooo**oooo
---~--~=O@@O@@O**oOO++*+~+--++++==+++=~ -+~~=*=***oOoOoooOOOoooooo*o
-    --+**oo+===*Oooo**+~=++++++==++++=~~~~+++o*+**oOo****oOOoooo*o*
      ~++oO+-~~~+@Oo***+====+++===+++=====+=+++******++**++*oOooo***
-     ~+***=~~--=ooo**+++oo*~~~~~~~~~+*+===+++=***+++*+++****oo***++
      -=***=~---~+oOo*+++==*o=+=~==+*+===+++**+***+**+=====+oo**+++=
   - --~**===~~-~~=*O*++===++*+===+==+++++++******o**=~~~===+**++++=
 -   --~+====- --~~=+*+++++++++==++==++++++++*****~=+=~~---=+**++===
-    --~======~~-~~ -===+++++**=++++++++++++=+++~=~~+=-----~=***+===
   -----~~+=*=~-~-~+- --~=++++++++++++++++=+-~- +=++~--~~-~==++*+===
-----~-~======~~-~~~~--   ~~~~~~==~===~=~~- --=~=o=~~~~~~~=++++++=++
~~--~--~~~==+++==~-- ~=-~--~~=~~~---~-~~-~-~~=+*=+=~~~-===++***+++=+
-~~~~~~~~~==++=++=--    -~~=++++===+=~==+==~**=+=~==~~=+*++****+++++
~~=~~~~~~~==++***+=--     --~=====++=~===+~~+~--~~~=++++****o*+****o
=====~~~~===+***oo*+-        - --------  --     -~=++*o*ooooo*+*oooO

If you squint really hard, you can almost discern the image. As of Maple 2018.1, ImageTools:-Preview now uses color output if interface(ansi) is set to true and interface(plotdevice) is set to colorchar:

> interface(plotdevice=colorchar):
> Preview(img);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

In addition to providing quick previews of image files, this feature can also be used to get more information about plots. For example, consider the following 3D plot generated using Maple's color character plot driver:

> plot3d([1,x,y],x=0..2*Pi,y=0..2*Pi,coords=toroidal(10));

                                                                        
                              ------------                              
                        ----------||-|----------                        
                     --------\-\\-||-|-//-/--------                     
                   ---------\\\\\|||-||/-///---------                   
                 --/-//-----\\\\||||-|||/////---\\\-\--                 
                -/-//-//-/-\\\\\||||||||//-/--\\\\-\\---                
               --|-||-||-|--\\\\||||||||////--|/||-||-|--               
              /--|-\-\-\\---\\\||||||||||///-////-/-/-|--\              
             //-----\------\\\\\||||||||////-------/-----\              
             //////--/--------\||||||||||/--------\--\\\\\\             
            /////// //// /-/--/-/-|-|||\-\--\-\ \\\\ \-\\\\\            
            |/////-////-/-//-/-/-|--|-|-\-\-\\-\-\\\\-\ \\\|            
            |//|////-/-// / /--|-|--|-|-|--\ \\-\-\ \\\\|\\|            
            ||| |-/-/  |-/--|-|--|  | | -|-|--\-|| \-\-| |||            
            |||-||| /-|--| |  | -|--|-|- |  | |--|-\ ||-||||            
            |||| |-|  | |--|--|--|  | |--|--|--| |  |-| ||||            
             |||-| |-||-|  |  |  ---|-|  |  |  |-||-| |-|||             
              ||-|-| | -|--|--|  |  | || |--|--|- | |-|-||/             
              \||| |-|- |  |  ---|--|--|--| |  | -|-| |-|/              
               \-|-| | -|--|-|| |   |  |  | |--|--| |-|//               
                \|||||- |  |-|--|---|--|--|-|  | -|-|||/                
                 \|\|-|-|--|--| |   |  |  |-|--|-|-|-|/                 
                   \\\|-|- |  |--|--|--|-|  | -|-|-//                   
                     --\-\-|--|--|--|-|--|--|-/-/--                     
                        ----\-|--|--|-|--|-/----                        
                              -\-|--|-|-/-                              
                                                                        

The output shows the general shape of the plot, but unless you already know what it looks like, it can be hard to visualize, especially since the character drivers don't support shading. One can glean additional insight by generating a high resolution bitmap version of the plot, and then Preview-ing that:

> interface(plotdevice="bmp",plotoutput="plot.bmp");
                          colorchar, terminal

> plot3d([1,x,y],x=0..2*Pi,y=0..2*Pi,coords=toroidal(10));
# Revert to colorchar or Preview won't generate a textual preview.
> interface(plotdevice="colorchar",plotoutput=terminal);
                             bmp, plot.bmp

> img := Read("plot.bmp");
                     [ 1..360 x 1..480 x 1..3 3-D Array ]
              img := [ Data Type: float[8]              ]
                     [ Storage: rectangular             ]
                     [ Order: C_order                   ]

> Preview(img);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

By default, Preview uses the extended xterm 256 color mode. The image is resized to fit within the current settings of interface(screenwidth) and interface(screenheight), and then each pixel is plotted using an "@" character over a colored background. The foreground and background colors are chosen so that their weighted average comes as close as possible to the actual RGB value of the pixel. Since this rarely produces exactly the right color, Preview also performs dithering, taking the error from the current pixel and distributing it over surrounding pixels. In effect, this uses spatial resolution to make up for the lack of color resolution.

ImageTools:-Preview has two keyword options, dither and sixteen, that let you override this behaviour. Passing the option dither=false will tell Preview not to dither. Passing sixteen=true (or just sixteen) will result in Preview using only the sixteen standard colors, of which only eight are used for the background.

The following examples are based on this Maple logo image:

By default, ImageTools:-Preview renders this with 256 colors and dithering as follows:

> img := Read("../../Pictures/logo.png");
                     [ 1..428 x 1..459 x 1..3 3-D Array ]
              img := [ Data Type: float[8]              ]
                     [ Storage: rectangular             ]
                     [ Order: C_order                   ]

> Preview(img);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

If we render it without dithering, the result is sharper, but the subtle gradient from lighter to darker blue turns into a series of very obvious concentric rings, as there are not enough distinct colors in the terminal's palette to render it accurately:

> Preview(img,dither=false);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

In sixteen color mode, the palette is severely reduced, and as a result, the dithering is much more pronounced as the per-pixel errors are larger:

> Preview(img,sixteen);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Finally, here is the image in sixteen color mode, with dithering disabled:

> Preview(img,sixteen,dither=false);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

One thing to note is that Maple has no way of knowing what the sixteen "standard" colors of your terminal actually look like, since many terminals let you change the palette. Maple assumes you are using the 16-color VGA palette, since that is close to the actual default palette on most terminals. If you are using a different palette (for example, Solarized), 16-color images will look worse than they are shown above.

Last week, in the first of a series of three articles, I demonstrated the new color syntax highlighting in the command line (TTY) interface of Maple 2018.1. This week, we'll look at a new facility for manipulating the command line history, the history meta-commands.

For the series of screen shots in this article, assume that the .maple_history file in your home directory initially contains the following:

    p1 := plot(sin,color="DeepPink"):
    p2 := plot(cos,color="DodgerBlue"):
    plots[display](p1,p2);

Now we'll start cmaple and execute a series of commands:

    |\^/|     Maple 2018.1 (X86 64 LINUX)
._|\|   |/|_. Copyright (c) Maplesoft, a division of Waterloo Maple Inc. 2018
 \  MAPLE  /  All rights reserved. Maple is a trademark of
 <____ ____>  Waterloo Maple Inc.
      |       Type ? for help.
> y := 1/(x^4+1);
                                     1
                              y := ------
                                    4
                                   x  + 1

> int(y,x);
     1/2           1/2             1/2           1/2
1/4 2    arctan(x 2    + 1) + 1/4 2    arctan(x 2    - 1)

                    2      1/2
            1/2    x  + x 2    + 1
     + 1/8 2    ln(---------------)
                    2      1/2
                   x  - x 2    + 1

> diff(%,x);
          1                       1              1/2
--------------------- + --------------------- + 2
       1/2     2               1/2     2
2 ((x 2    + 1)  + 1)   2 ((x 2    - 1)  + 1)

    /         1/2        2      1/2              1/2 \
    |  2 x + 2         (x  + x 2    + 1) (2 x - 2   )|
    |--------------- - ------------------------------|
    | 2      1/2               2      1/2     2      |
    \x  - x 2    + 1         (x  - x 2    + 1)       /

      2      1/2        /      2      1/2
    (x  - x 2    + 1)  /  (8 (x  + x 2    + 1))
                      /

> simplify(%);
memory used=5.2MB, alloc=41.3MB, time=0.11
                                 4
                                x  + 1
                 -------------------------------------
                   2      1/2     2     1/2    2     2
                 (x  + x 2    + 1)  (x 2    - x  - 1)

> normal(%,expanded);
                                   1
                                 ------
                                  4
                                 x  + 1

There are two parts to the history:

  1. Session history consists of the commands you've entered in the current session.
  2. Command history consists of all commands from previous sessions, together with the session history (up to a maxium specified by interface(historysize), which is 1000 lines by default).

History meta-commands all begin with two exclamation marks at the beginning of the line. The !!= meta-command lists the session history:

> !!=
<< y := 1/(x^4+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

Notice that each displayed line of the history is preceeded by << to differentiate it from Maple input and other Maple output. Each meta-command also has a long form. The long form for !!= is !!list:

> !!list
<< y := 1/(x^4+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

Most meta-commands can take an argument specifying the amount of history to be affected. For example, a numeric argument refers to the last lines of the command history. Here, !!=8 includes the 3 lines from the previous history, as well as the 5 lines of session history:

> !!=8
<< p1 := plot(sin,color="DeepPink"):
<< p2 := plot(cos,color="DodgerBlue"):
<< plots[display](p1,p2);
<< y := 1/(x^4+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

An argument beginning with a forward slash ("/") refers to all history lines beginning with the most recent one that contains the text entered after the slash (if the text to be searched for does not begin with a space or a digit, the slash can be omitted):

> !!=/diff
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

We'll quit Maple and start a new session to illustrate another aspect of the history meta-commands.

> quit
memory used=6.4MB, alloc=41.3MB, time=0.14

In the new session, the meta-command !!=/x^4 will list everyting from the previous session starting from the most recent matching line:

    |\^/|     Maple 2018.1 (X86 64 LINUX)
._|\|   |/|_. Copyright (c) Maplesoft, a division of Waterloo Maple Inc. 2018
 \  MAPLE  /  All rights reserved. Maple is a trademark of
 <____ ____>  Waterloo Maple Inc.
      |       Type ? for help.
> !!=/x^4
<< y := 1/(x^4+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

If a !!= meta-command with a numeric or search argument is executed as the first command in a fresh session, not only is the specified amount of command history listed, but that part of the history is then considered to be session history. Executing just !!= with no argument shows that this is the case:

> !!=
<< y := 1/(x^4+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

The !!! meta-command (long form !!play) re-executes the entire session history:

> !!!
>> y := 1/(x^4+1);
                                     1
                              y := ------
                                    4
                                   x  + 1

>> int(y,x);
     1/2           1/2             1/2           1/2
1/4 2    arctan(x 2    + 1) + 1/4 2    arctan(x 2    - 1)

                    2      1/2
            1/2    x  + x 2    + 1
     + 1/8 2    ln(---------------)
                    2      1/2
                   x  - x 2    + 1

>> diff(%,x);
          1                       1              1/2
--------------------- + --------------------- + 2
       1/2     2               1/2     2
2 ((x 2    + 1)  + 1)   2 ((x 2    - 1)  + 1)

    /         1/2        2      1/2              1/2 \
    |  2 x + 2         (x  + x 2    + 1) (2 x - 2   )|
    |--------------- - ------------------------------|
    | 2      1/2               2      1/2     2      |
    \x  - x 2    + 1         (x  - x 2    + 1)       /

      2      1/2        /      2      1/2
    (x  - x 2    + 1)  /  (8 (x  + x 2    + 1))
                      /

>> simplify(%);
memory used=5.2MB, alloc=41.3MB, time=0.10
                                 4
                                x  + 1
                 -------------------------------------
                   2      1/2     2     1/2    2     2
                 (x  + x 2    + 1)  (x 2    - x  - 1)

>> normal(%,expanded);
                                   1
                                 ------
                                  4
                                 x  + 1

Notice that each command is displayed with a >> prompt. This prompt is used whenever a command in the history is being played back.

History commands can be played back one step at a time using the !!. (or !!step) meta-command. Each command is displayed with the >> prompt, and you are given the opportunity to edit it before pressing Enter to execute it. Here, we've changed the exponent of from 4 to 3 before pressing Enter, and then pressed Enter four more times to re-execute the remaining commands:

> !!.
>> y := 1/(x^3+1);
                                     1
                              y := ------
                                    3
                                   x  + 1

>> int(y,x);
                                                                  1/2
                          2                 1/2        (2 x - 1) 3
  1/3 ln(x + 1) - 1/6 ln(x  - x + 1) + 1/3 3    arctan(--------------)
                                                             3

>> diff(%,x);
                1          2 x - 1               2
            --------- - -------------- + ------------------
            3 (x + 1)       2              /         2    \
                        6 (x  - x + 1)     |(2 x - 1)     |
                                         3 |---------- + 1|
                                           \    3         /

>> simplify(%);
                                   1
                          --------------------
                                    2
                          (x + 1) (x  - x + 1)

>> normal(%,expanded);
                                   1
                                 ------
                                  3
                                 x  + 1

When editing a command prefixed with the >> prompt, the command is edited in-place in the history. In other words, the history is permanently modified. History meta-commands are not played back (or infinite loops could result), and lines containing only comments are displayed but not offered for editing.

Still in the same session, let's use !!. with a search pattern to generate and display the plots from the older history, pressing Enter after each command:

> !!./p1 :=
>> p1 := plot(sin,color="DeepPink"):
>> p2 := plot(cos,color="DodgerBlue"):
>> plots[display](p1,p2);

                                                                        
                                    |                                   
 -*\    /*-*                      1-+*     *-*\                     /*- 
   \   //  \\                    // |\\   /   \                     /   
    \  /    \\                   /  | \  //    \                   /    
    \ /      *                  *   |  * *     \\                  /    
     **      ||                 |   |  |*       *                 *     
     *|       |                |    |   *       ||               ||     
     ||       ||               |    |  |*        |               |      
    |||        |              |     |  | |       |               |      
    | ||       |              |     | || |        |             ||      
    |  |       ||            || 0.5 | |  |        |             |       
   |   |        |            |      | |   |       |             |       
   |   ||       |            |      |||   |        |           ||       
   |    |       ||           |      ||    |        |           |        
  |     |        |          |       ||     |       |           |        
  |     ||       |          |       ||     |        |         ||        
  |      |       ||         |       |      |        |         |         
 ||      |        |        |        |       |       |         |         
 |       ||       |        |        |       |       ||       ||         
 +--------+-------++-------+-------++-------+--------+-------+--------+ 
  -6      |  -4    |    -2|       0||        |2      |   4   |      6|| 
          ||       |      |        ||        |       ||     ||       |  
           |       |      |       | |        |        |     |        |  
           |        |    ||       | |        ||       |     |       ||  
           |        |    |        | |         |       ||    |       |   
            |       |    |       || |         |        |   |        |   
            |        |  ||       |  |         ||       |   |        |   
            |        |  |      -0.5 |          |       ||  |       |    
             |       |  |       ||  |          |        | |        |    
             |        |||       |   |          ||       | |       ||    
             ||       ||        |   |           |       |*|       |     
              |       **       |    |           |        *        |     
              |*      |*       |    |            |      **|      *      
               \     /*\\     *     |            *\     / *      /      
               \\    /  \    //     |             \    // \\    /       
                \\  //   \   /      |             \\   /   \\  //       
                 *-*/    \*-*    -1 |              \*-*     *-*/        
                                    |                                   
                                                                        

>> !! y := 1/(x^3+1);
> _

On the last line above, we typed !! followed by a space (long form !!stop) to tell Maple to stop playing back commands and give a fresh prompt. If we now issue !!=, we see that the session history still contains only the five commands it contained originally. The played back commands were not appended to the history:

> !!=
<< y := 1/(x^3+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);

Issuing a new command at the regular > prompt adds it to the end of the session history:

> sin(Pi/2) + 1;
                                   2

> !!=
<< y := 1/(x^3+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);
<< sin(Pi/2) + 1;

The !!- (or !!drop) meta-command deletes one or more commands from the history:

> !!-
> !!=
<< y := 1/(x^3+1);
<< int(y,x);
<< diff(%,x);
<< simplify(%);
<< normal(%,expanded);
> !!-/simpl
> !!=
<< y := 1/(x^3+1);
<< int(y,x);
<< diff(%,x);

In addition to the meta-commands described above for manipulating the history within a session, there are three meta-commands to copy history to and from files:

  • !!> (or !!save ) writes the session history to the specified file.
  • !!< (or !!read ) replaces the session history with the contents of the specified file.
  • !!+ (or !!append ) appends the contents of the specified file to the session history.

Used together, these meta-commands let you save important sessions for later examination or reuse without relying on the .maple_history file, or let you make large changes to the current session history using your favorite text editor.

The !!? (or !!help) meta-command displays a short summary of all the meta-commands:

> !!?

The sequence "!!" at the beginning of a line introduces a history meta-command.
Each has a short or long form (shown below in parentheses). The long form name
may be used instead of the single character appearing after "!!".

!!=specifier    - list session history or specified lines (list)
!!!specifier    - play back session history or specified lines (play)
!!.specifier    - step through session history or specified lines (step)
!!-specifier    - drop one or specified lines from history (drop)
!!<filename     - read file into session history (read)
!!+filename     - append file to session history (append)
!!>filename     - save session history to file (save)
!!?             - help for history meta-commands (help)
!!              - stop the single-step playback in progress (stop)

The 'specifier' is optional. If present, it can be an integer, N, referring to
the N most recent command lines, or a string beginning with a "/" character,
referring to the lines from the most recent one containing that string. The "/"
may be omitted if the search string does not begin with a space or digit.

Detailed information can be found in the ?edit_history help page.

For the past two years the Queen’s College of Guyana Alumni Association (NY) has been hosting its Queen’s College Summer Maths Institute, and Maplesoft has supported this initiative by giving students access to Maple.   With Dr. Terrence Blackman at its helm, the institute aims to sustainably implement a developmentally appropriate and culturally resonant middle school learning environment that engages Guyanese students in a cognitively rich mathematics learning experience.  The experience is intended to place them securely on pathways to STEM (Science, Technology, Engineering and Math) excellence.

The program uses a developmentally appropriate approach that combines significant mathematical content with a setting that encourages a sense of discovery and excitement about math through problem solving and exploration. Program Manager Shindy Johnson, a former student of Queens College, noted that by the end of the first week math sceptics fall in love and gained confidence, and math lovers renew their passion.

As avid Maple users, Dr. Terence Blackman and Cleveland Waddell, one of the main organizers and lecturer,  give the students the opportunity to use Maple. Last year, the students were amazed by Maple's computational power. “It was nothing like they have seen before.  Many students also wrote their first lines of computer code using Maple during the summer camp.  Maple is an invaluable resource for us during the camp,” said Waddell.

Dr. Terence Blackman and Cleveland Waddell

Students receive further enrichment through field trips to broaden their appreciation for education and industry in Guyana.  In addition, Guyanese professionals visit the Institute to share their expertise, career journeys and practical applications of math and other STEM disciplines in their professions.

Field trip to Uitvlugt Sugar Estate

Students who participate ranged from self-professed math lovers to teens who confessed to fearing and even loathing math. By the end of the first week, math lovers had discovered even greater “beauty in the mathematics” and those who quaked at the thought of math were beginning to commit – with confidence – to improving their math grades. This year’s Queen’s College Summer Maths Institute will take place July 26-August 3, 2018 in Georgetown, Guyana.   

The Maple command line interface (cmaple), often referred to as the "TTY interface" for its original use on Teletype terminals, is still the tool of choice for many Maple developers and power users. Maple 2018.1 introduces several new capabilities to this long-lived interface:

This post, the first in a series of three, will address color syntax highlighting. We'll start with a very short sample session:

    |\^/|     Maple 2018.1 (X86 64 LINUX)
._|\|   |/|_. Copyright (c) Maplesoft, a division of Waterloo Maple Inc. 2018
 \  MAPLE  /  All rights reserved. Maple is a trademark of
 <____ ____>  Waterloo Maple Inc.
      |       Type ? for help.
> piecewise(4 < x^2 and x < 8, f(x));
                            {                  2
                            { f(x)        4 < x  and x < 8
                            {
                            {  0             otherwise

> p := unapply(%,x);
                                               2
                      p := x -> piecewise(4 < x  and x < 8, f(x))

> 1/p(1);
Error, numeric exception: division by zero
> quit
memory used=5.3MB, alloc=41.3MB, time=0.07

In the above example, you can see that general keywords are in bold blue, variables in italics (not supported by all terminals), error messages in bold red, control flow interrupting keywords in bold magenta, and memory usage messages in normal blue.

Color syntax highlighting is turned on by default in cmaple for Linux and OS/X if the terminal you are using (as specified by the TERM environment variable) is known to support it. It is currently turned off by default under Windows. It can be explicitly turned on or off for 2D and message output using interface(ansi=) where is true or false (under Windows, you can put interface(ansi=true) in your maple.ini file to automatically turn it on). Likewise, interface(ansilprint=) controls highlighting for 1D output (such as that produced by lprint), and interface(ansiedit=) for input.

Not all terminals support all possible highlighting modes. The following two commands show what colors your terminal can display, and how they are used by Maple's syntax highlighting:

> interface(showtermcolors):

ANSI X3.64 Standard Attributes

Normal  Bold  Italic  Underlined  Reverse  

System Colors (0-15) Using ANSI Escape Sequences

Color00  Color01  Color02  Color03  Color04  Color05  Color06  Color07  
Color08  Color09  Color10  Color11  Color12  Color13  Color14  Color15  

System Colors (0-15) Using Extended Escape Sequences

  0    0    1    1    2    2    3    3    4    4    5    5    6    6    7    7  
  8    8    9    9   10   10   11   11   12   12   13   13   14   14   15   15  

Extended 6x6x6 Color Cube (16-231)

 16   16   17   17   18   18   19   19   20   20   21   21  
 22   22   23   23   24   24   25   25   26   26   27   27  
 28   28   29   29   30   30   31   31   32   32   33   33  
 34   34   35   35   36   36   37   37   38   38   39   39  
 40   40   41   41   42   42   43   43   44   44   45   45  
 46   46   47   47   48   48   49   49   50   50   51   51  

 52   52   53   53   54   54   55   55   56   56   57   57  
 58   58   59   59   60   60   61   61   62   62   63   63  
 64   64   65   65   66   66   67   67   68   68   69   69  
 70   70   71   71   72   72   73   73   74   74   75   75  
 76   76   77   77   78   78   79   79   80   80   81   81  
 82   82   83   83   84   84   85   85   86   86   87   87  

 88   88   89   89   90   90   91   91   92   92   93   93  
 94   94   95   95   96   96   97   97   98   98   99   99  
100  100  101  101  102  102  103  103  104  104  105  105  
106  106  107  107  108  108  109  109  110  110  111  111  
112  112  113  113  114  114  115  115  116  116  117  117  
118  118  119  119  120  120  121  121  122  122  123  123  

124  124  125  125  126  126  127  127  128  128  129  129  
130  130  131  131  132  132  133  133  134  134  135  135  
136  136  137  137  138  138  139  139  140  140  141  141  
142  142  143  143  144  144  145  145  146  146  147  147  
148  148  149  149  150  150  151  151  152  152  153  153  
154  154  155  155  156  156  157  157  158  158  159  159  

160  160  161  161  162  162  163  163  164  164  165  165  
166  166  167  167  168  168  169  169  170  170  171  171  
172  172  173  173  174  174  175  175  176  176  177  177  
178  178  179  179  180  180  181  181  182  182  183  183  
184  184  185  185  186  186  187  187  188  188  189  189  
190  190  191  191  192  192  193  193  194  194  195  195  

196  196  197  197  198  198  199  199  200  200  201  201  
202  202  203  203  204  204  205  205  206  206  207  207  
208  208  209  209  210  210  211  211  212  212  213  213  
214  214  215  215  216  216  217  217  218  218  219  219  
220  220  221  221  222  222  223  223  224  224  225  225  
226  226  227  227  228  228  229  229  230  230  231  231  

Extended 24-Level Grayscale (232-255)

232  232  233  233  234  234  235  235  236  236  237  237  238  238  239  239  
240  240  241  241  242  242  243  243  244  244  245  245  246  246  247  247  
248  248  249  249  250  250  251  251  252  252  253  253  254  254  255  255  

If your terminal does not support 256 color mode, then many of the colored blocks shown above will appear differently or not at all.

> interface(showcolors):

 1 Normal output:           evalf(1/2) = 0.5
 2 Italics (variables):     x, y, z
 3 Symbol text (not used):  symbol
 4 Bold (fallback):         Begin, be bold, and venture to be wise.
 5 Underlined (fallback):   Morality, like art, means drawing a line someplace.
 6 Reversed (not used):      The reverse side also has a reverse side. 
 7 Input prompts:           >  DBG>
 8 User input:              1/(x^4+1);
 9 Userinfo output:         message, x, y
10 Trace output:            {--> enter f, args = x, y
11 Warning messages:        Warning, x is implicitly declared local
12 Error messages:          Error, (in f) invalid subscript selector
13 Debugger output:         No breakpoints set
14 General Maple keywords:  for  from  to  while  do  until
15 Declaration keywords:    local  option  description
16 Flow interruptions:      break  return
17 Exception keywords:      error  try  catch
18 Subexpression labels:    %1  %2
19 Special & quoted names:  thisproc  `diff/sin`
20 String literals:         "Hello, world!"
21 Maple startup message:   Maple 2019
22 Output from printf:      x=1.234 y=5.678
23 Status messages:         memory used=1.7MB, alloc=8.3MB, time=0.03
24 System command output:   1466  4739  43140  myprog.mpl
25 Maple comments:          # Comments are free but facts are sacred.

The colors used for the different categories of output as listed by the command above are user selectable. The default is to use only the sixteen ANSI X3.64 standard colors (or Windows command prompt standard colors). These may appear differently than shown here depending on the color palette of your terminal window.

The color settings can be queried or set as follows:

> currentColors := interface(ansicolor);
currentColors := [-1, -1, -1, -1, -1, -1, 2, -1, 2, 3, 11, 9, 6, 12, 10, 13, 9, 14, 6,

    5, 2, 136, 4, 134, 3]

# Individual colours, as numbered in the output of interface(showcolors), can
# be changed. Let's make keywords bright yellow:
> myColors := subsop(14=226,currentColors);
myColors := [-1, -1, -1, -1, -1, -1, 2, -1, 2, 3, 11, 9, 6, 226, 10, 13, 9, 14, 6, 5,

    2, 136, 4, 134, 3]

> interface(ansicolor=myColors);
[-1, -1, -1, -1, -1, -1, 2, -1, 2, 3, 11, 9, 6, 12, 10, 13, 9, 14, 6, 5, 2, 136, 4,

    134, 3]

> piecewise(4 < x^2 and x < 8, f(x));
                            {                  2
                            { f(x)        4 < x  and x < 8
                            {
                            {  0             otherwise

There are several predefined color schemes that can be selected using interface(ansicolor=), where is an integer from 0 to 6. Scheme 0, the default, should work on any terminal. Of the remaining schemes, the odd numbered ones are designed to look good on light backgrounds, and the even numbered ones on dark backgrounds.

There is also a new character plot driver, selectable using interface(plotdevice=colorchar), which supports character plotting in color. Colors are mapped to the nearest color supported by the terminal:

> interface(plotdevice=colorchar):
> p1 := plot(sin(x),x=-Pi..Pi,thickness=1,color="DeepPink"):
> p2 := plot(sin(x)+sin(3*x)/3,x=-Pi..Pi,thickness=2,color="LawnGreen"):
> p3 := plot(sin(x)+sin(5*x)/5,x=-Pi..Pi,thickness=3,color="DodgerBlue"):
> plots[display](p1,p2,p3);

                                                                                       
                                           |                                           
                                           |                  @@@@@                    
                                           |                 @@   @@                   
                                           |                 @     @                   
                                         1 |                *.......*                  
                                           |       *******.*@       @*..******         
                                           |      **    .**@         @**.    **        
                                           |     **   ..  ***       ***  ..   **       
                                           |    **   ..  @@ **** **** @@  ..   **      
                                           |    *   ..  @@     ***     @@  ..   *      
                                           |   *@@@**@@@                 @@@**@@@*     
                                       0.5 |  **@ ..                         .. @**    
                                           |  *@ ..                           .. @*    
                                           | ** .                               . **   
                                           | * .                                 . *   
                                           |**..                                 ..**  
                                           |*..                                   ..*  
                                           |*.                                     .*  
                                           *.                                       .* 
 **---------------------------------------**-----------------------------------------* 
  -3           -2            -1          0*|            1             2            3   
  *..                                   ..*|                                           
  **..                                 ..**|                                           
   * .                                 . * |                                           
   ** ..                              . ** |                                           
    *@ ..                           .. @*  |                                           
    **@ ..                         .. -0.5 |                                           
     *@@@**@@@                 @@@**@@@*   |                                           
      *   ..  @@     ***     @@  ..   *    |                                           
      **   ..  @@ **** **** @@  ..   **    |                                           
       **   ..  @**       **@  ..   **     |                                           
        **    .**@         @**.    **      |                                           
         *******.*@       @*.*******       |                                           
                  *.......*             -1 |                                           
                   @     @                 |                                           
                   @@   @@                 |                                           
                    @@@@@                  |                                           
                                           |                                           
                                                                                       

> plot3d([1,x,y],x=0..2*Pi,y=0..2*Pi,coords=toroidal(10));

                                                                                       
                                  -------------------                                  
                             --------\\\-|-|-|-///--------                             
                          ---------\\\-\-|-|-|-/-///---------                          
                        ----------\\\-\-||-|-||-/-///----------                        
                      /-/-/-/-----\\\\\-|||||-|-/////------------                      
                     -//-/-/-/---\-\\-\||-|||-||/-//-/---\-\-\-\--                     
                   --//-|||-/-/--\\\\\\|||||||-|//////--\-\-|||\|\-\                   
                  /---||-||||-|--\\-\\\|||||||||///-//--|-||||--|---\                  
                 /--|--\-\-\-\\--\\/\\|||||||||||//-//-|-///-/-/--|--\                 
                //-//--\\-\-----\-\\\\|||||||||||////-///////-//--\\-\\                
                |//\/\------------\\\|||||||||||||////-------//--/\\\\|                
               /// / / -- /--- -----\|||||||||||||/---------\ --/\ \\\\\               
               //\/ /-//-/-//-//-/--/-/--/-|-\--\-\--\-\\-\\-\-\\/\ \/\\               
               ///\/ /--/ //-// /--/--/-|--|--|-\--\--\ \\-\\ \--\ \/\\\               
               /||/-// /--/  /--/-//-|  |  |  |  |-\\-\--\  \\-\ \\/\||\               
               || |-/ /  /--/  /  | -|--|--|--|--|- |  \ -\--\  \ \/| |||              
              |||| | -/ /  ||--/-||- |  |  |  |  | -||--\  | \\-\- | |/|               
               |||-| | -/--|  |  |  -|--|--|--|---|  |  |  |--\  | |/|||               
               |\| |-|  | ||--|- |  |   |  |  |   |  | -|--|| |  |-- |/|               
               |\||  |-|  |  |  -|--|---|--|---|--|--|-  |  |  |-|  ||/|               
               \|-| |  |--|- |   |  |  |   |   |  |  |   | -|--| |  |/|/               
                \||-|- |  |--|--|-  |  |   |   |  |  -|--|--|  | -|-||/                
                \|-|||-|- |  |  | --|--|---|---|--|-- |  |  |  |-|||/|/                
                 \\|-| |--|--|  |   |  |   |   |  |   |  |--|--| |-|//                 
                  \\ |-|  |  |--|---|  |   |   |  |---|--|  |  |-| //                  
                   -\| |--|  |  |   |--|---|---|--|   |  |  |--| |//                   
                     \|-| |--|--|   |  |   |   |  |   |--|--| |-|/                     
                      \\|\|| |  |---|--|---|---|--|---|  | ||-|//                      
                        -\----|--|  |  |   |   |  |  |--|----/-                        
                          --\-\\ |--|--||--|---|--|--|  /-/--                          
                             ----\\-||--|--|--|---|--///--                             
                                  \--\--|--|--|--/--/                                  
                                                                                       

For more details, please refer to the help page, ?ansicolor.

Hi MaplePrimes Users!

It’s your friendly, neighborhood tech support team; here to share some tips and tricks from issues we help users with on a daily basis.

A customer contacted us through a Help Page feedback form, asking how to add a row or column in a Matrix. The form came from the Row Operations help page, but the wording of the message suggested that the customer actually wanted to insert a new row or column altogether. Such manipulations can often be accomplished by a command in the ArrayTools package, but the only Insert command currently available is the one for Vectors and 1-D Arrays. Using the Concatenate command from that package, and various commands from the LinearAlgebra package (including the SubMatrix command), we were able to write two custom procedures to perform these manipulations:

InsertRow := proc (A::rtable, n::integer, v::Vector[row])
    local R, C, top, bottom;
    uses LinearAlgebra;
    R := RowDimension(A); C := ColumnDimension(A);
    top := SubMatrix(A, [1 .. n-1], [1 .. C]);
    bottom := SubMatrix(A, [n .. R], [1 .. C]);
    return ArrayTools:-Concatenate(1, top, v, bottom);
end proc:

InsertColumn := proc (A::rtable, n::integer, v::Vector[column])
    local R, C, left, right;
    uses LinearAlgebra;
    R := RowDimension(A); C := ColumnDimension(A);
    left := SubMatrix(A, [1 .. R], [1 .. n-1]);
    right := SubMatrix(A, [1 .. R], [n .. C]);
    return ArrayTools:-Concatenate(2, left, v, right)
end proc:

# test cases:

M := Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]):
v := Vector[row]([2, 2, 2]):
v2 := Vector[column]([2, 2, 2]):
seq(InsertRow(M, i, v), i = 1 .. 4);
seq(InsertColumn(M, i, v2), i = 1 .. 4);

We then reworked this problem using some handy indexing and construction notation that allows our previous procedures to save on the variable constructions and syntax:

InsertRow := proc( A :: rtable, V :: Vector[row], r :: posint )
    return < A[1..r-1,..]; V; A[r..-1,..] >:
end proc:

InsertColumn := proc( A :: rtable, V :: Vector[column], c :: posint )
    return < A[..,1..c-1] | V | A[..,c..-1] >:
end proc:

M := Matrix(3, 3, [seq(i, i = 1 .. 9)]);
A := convert(M, Array);
U := Vector[row]( [ a, b, c ] );
V := convert( U, 'Vector[column]' );
seq(InsertRow( A, U, i ), i=1..4);
seq(InsertColumn( A, V, i ), i=1..4);
seq(InsertRow( M, U, i ), i=1..4);
seq(InsertColumn( M, V, i ), i=1..4);

In order to explore the use of signal processing package in image processing, @Samir Khan and I created this application that performs discrete Haar wavelet transform on images to achieve both lossy (irreversible) and lossless (reversible) compression.

Haar wavelet compression modifies the image matrix to increase the number of zero entries in the matrix, which results in a sparse matrix that can be stored more efficiently, thus reducing the file size. A Haar wavelet transform groups adjacent items in the matrix, stores the average and difference of the two numbers. Notice that this computation is reversible since knowing the values of a, b and given that x1-x2 = a; (x1+x2)/2 = b, we can solve for x1 and x2. Haar wavelet compression is taking advantage of the property that neighboring pixels in an image usually share very similar value; hence recursively applying Haar wavelet transform to the rows and columns of an image matrix significantly increases the number of zero entries. In the application we achieved a compression ratio of 1.296 (number of non-zero entries in original: number of non-zero entries in processed matrix).

The fact that Haar wavelet transform is reversible means that we can use it to perform lossless image compression: the decompressed image will be exactly the same as the image before compression. Transmission and temporary storage of the data would be made more efficient without any loss of details in the image.

But what if the file size is still too big or we simply don’t need that many details in the image? That is when lossy compression comes into use. By omitting some details/fidelity, lossy compression is able to achieve notably smaller file size. In this application, we apply a filter to the transformed image matrix, setting entries that are close to zeros to actual zeros (i.e. pick a positive number ϵ such that all x < ϵ are changed to 0 in the matrix). The value of ϵ directly impacts the quality of the decompressed image so should be chosen carefully in practice. In this application, we chose ϵ = 0.01, which results in a compression ratio of 19.38, but instead produces a very blurry image after reversing the compression.

(left: Original image, right: lossy compression with ϵ = 0.01)

The application can be accessed here for more details.

In an attempt to explore the field of image processing, @Samir Khan and I created an application (download here) that demonstrates the removal of two types of noises from an image through frequency and spatial filtering.

Periodic noises and salt & pepper noises are two common types of image noises, usually caused by errors during the image capturing or data transmission process. Periodic noises result in repetitive patterns being added onto the original image, while salt & pepper noises are the irregular appearance of dark pixels in the bright area and bright pixels in the dark area of the image. In this application, we artificially generate these noises and pollute a clean picture in order to demonstrate the removal techniques.

(Fig 1: Picture of Waterloo Office taken by Sophie Tan            Fig 2: Converted to greyscale for processing, added two noises)

In order to remove periodic noises from the image, we apply a 2D Fourier Transform to convert the image from spatial domain to frequency domain, where periodic noises can be visually detected as separate, discrete spikes and therefore easily removed.

(Fig 3 Frequency domain of the magnitude of the image)

One way to remove salt and pepper noises is to apply a median filter to the image. In this application, we run a 3 by 3 kernel across the image matrix that sorts and places the median among the 9 elements as the new matrix entry, thus resulting in the whole image being median-filtered.

Comparison of the image before and after noise removal:

Please refer to the application for more details on the implementation of the two removal techniques.

 

Hello, everyone! My name’s Sophie and I’m an intern at Maplesoft. @Samir Khan asked me to develop a couple of demonstration applications using the DeepLearning package - my work is featured on the Application Center

I thought I’d describe two critical commands used in the applications – DNNClassifier() and DNNRegressor().

The DNNClassifier calls tf.estimator.DNNClassifier from the Tensorflow Python API. This command builds a feedforward multilayer neural network that is trained with a set of labeled data in order to perform classification on similar, unlabeled data.

Dataset used for training and validating the classifier has the type DataFrame in Maple. In the Prediction of malignant/benign of breast mass example, the training set is a DataFrame with 32 columns in total, with column labels: “ID Number”, “Diagnosis”, “radius”, “texture”, etc. Note that labeling the columns of the dataset is mandatory, as later the neural network needs to identify which feature column corresponds to which list of values.

Feature columns are what come between the raw input data and the classifier model; they are required by Tensorflow to specify how the input data should be transformed before given to the model. Maple now supports three types of Feature Columns, including:

  • NumericColumn that represents real, numerical figure,
  • CategoricalColumn that denotes categorical(ordinal) data
  • BucketizedColumn that organizes continuous data into a discrete number buckets with specified boundaries.

In this application, the input data consists of 30 real, numeric values that represents physical traits of a cell nucleus computed from a digitized image of the breast mass. We create a list of NumericColumns by calling

with(DeepLearning):
fc := [seq(NumericColumn(u,shape=[1]), u in cols[3..])]:

where cols is a list of column labels and shape[1] indicates that each data input is just a single numeric value.

When we create a DNNClassifier, we need to specify the feature columns (input layer), the architecture of the neural network (hidden layers) and the number of classes (output layer). Recall that the DNNClassifier builds a feedforward multilayer neural network, hence when we call the function, we need to indicate how many hidden layers we want and how many nodes there should be on each of the layer. This is done by passing a list of non-negative integers as the parameter hidden_units when we call the function. In the example, we did:

classifier := DNNClassifier(fc, hidden_units=[20,40,20],num_classes=2):

where we set 3 hidden layer each with 20, 40, 20 nodes respectively. In addition, there are 30 input nodes (i.e. the number of feature columns) and 1 output node (i.e. binary classification). The diagram below illustrates a simpler example with an input layer with 3 nodes, 2 hidden layers with 7, 5 nodes and an output layer with 1 node.

(Created using NN-SVG by https://github.com/zfrenchee/NN-SVG)

After we built the model, we can train it by calling

classifier:-Train(train_data[3..32], train_data[2], steps = 256, num_epochs = 3, shuffle = true):

where we

  1. Give the training data (train_data[3..32]) and the corresponding labels (train_data[2]) to the model.
  2. Specified that the entire dataset will be passed to the model for three times and each iteration has 256 steps.
  3. Specified that data batches for training will be created by randomly shuffling the tensors.

Now the training process is complete, we can use the validation set to evaluate the effectiveness of our model.

classifier:-Evaluate(test_data[3..32],test_data[2], steps = 32);

The output indicates an accuracy of ~92.11% in this case. There are more indices like accuracy_basline, auc, average_loss that help us decide if we need to modify the architecture for better performance.

We then build a predictor function that takes an arbitrary set of measurements as a DataSeries and returns a prediction generated by the trained DNN classifier.

predictor := proc (ds) classifier:-Predict(Transpose(DataFrame(ds)), num_epochs = 1, shuffle = false)[1] end proc;

Now we can pass a DataSeries with 30 labeled rows to the predictor: (Recall the cols is a list of the column names)

ds := DataSeries([11.49, 14.59, 73.99, 404.9, 0.1046, 8.23E-02, 5.31E-02, 1.97E-02, 0.1779, 6.57E-02, 0.2034, 1.166, 1.567, 14.34, 4.96E-03, 2.11E-02, 4.16E-02, 8.04E-03, 1.84E-02, 3.61E-03, 12.4, 21.9, 82.04, 467.6, 0.1352, 0.201, 0.2596, 7.43E-02, 0.2941, 9.18E-02], labels = cols[3..]); 
predictor(ds);

The output indicates that the probability of this data being a class _id [0] is ~90.79%. In other words, according to our model, the probability of this breast mass cell being benign is ~90.79%.

The use of the DNNRegressor is very similar (almost identical) to that of the Classifier, the only significant difference is that while the Classifier predicts discrete labels as classes, the Regressor predicts a continuous qualitative result with the provided data (Note that CategoricalColumn is still applicable). For more details about the basic usage of the DNNRegressor, please refer to Predicting the burnt area of a forest fires with DNN Regressor.

 

We have just released a new version of MapleSim.  The MapleSim 2018 family of products offers new tools for developing digital twins, greater connectivity with other modeling tools, and expanded modeling scope. Improvements include:

  • New tools for creating motion profiles
  • FMI  import for FMI 2.0 Fixed-Step Co-Simulation
  • Optimized handling of large models
  • Inclusion of temperature effects in the MapleSim Hydraulics Library from Modelon and MapleSim Pneumatics Library from Modelon
  • Heat transfer through air and water with the MapleSim Heat Transfer Library from CYBERNET

See What’s New in MapleSim 2018 for more information about these and other improvements.

Who should be considered an 'expert'? How does one achieve expert status? In this guest MaplePrimes blog post, 'Understanding Maple' author Ian Thompson discusses his view of what makes an expert, his journey of becoming an expert in Maple, and the process of putting together and perfecting this resource for Maple users.

 

In days of 8-bit computers, one would sometimes encounter individuals who knew everything about a particular device or piece of software. Single programmers wrote entire applications or games, and some could debug their work by looking directly at a core dump (a printout of the numbers stored in the computer’s memory). Some even managed to take computers beyond their specifications by exploiting design loopholes that the manufacturers hadn’t foreseen or intended. It would be fair to classify such individuals as ‘experts’.

Fast forward twenty five years, and the picture is far less clear. The complexity of computers and software has grown to such an extent that even relatively small smartphone applications are created by teams of developers, and nobody understands every aspect of a CPU chip, much less an entire PC or tablet. Who now should be classified as an expert? One possibility is that an expert is a person who may sometimes need to look up the details of a rarely used command or feature, but who is never confused or frustrated by the behavior of the system or software in question (except where there is a bug), and never needs help from anyone, except perhaps on rare occasions from its creators.

This rather stringent definition makes me an expert in only two areas of computing: the Fortran programming language, and the mathematical computation system Maple. An argument could be made for the typesetting system LATEX, but whilst this has a large number of expert users, there is also a much smaller group of more exalted experts, who maintain the system and develop new packages and extensions. It would be fair to say that I fall into the first category, but not the second.*

How does one achieve expert status? Some software actively prevents this, by hiding its workings to such an extent that fully understanding its behavior is impossible. Where it is possible to gain expert status, I have experienced two very different routes, both starting during my time as a research student, when it became clear that Fortran and Maple would be useful in my work. There were several parallels. I knew a little about both, having used them for basic tasks as an undergraduate. However, working out why things went wrong and how to fix them was time-consuming and unrewarding, since it often relied on magic recipes obtained from unreliable sources, and in many cases I didn’t really understand why these worked, any more than I understood why my own attempts had not. I realized then that knowing a little was at the root of these problems. Partial knowledge, supplemented by contradictory, outdated and even downright bad advice from websites and well-meaning individuals (some of whom invariably labor under false pretences of their own expert status) is not an efficient way to approach scientific computing. In fact it’s just a recipe for frustration. In the case of Fortran, fixing this turned out to be easy, because there are lots of good books on the subject. Reading one of these eliminated all of my problems with the language at a stroke. I can’t claim that I remembered every command and its syntax, nor do I know them all now. This is hardly surprising — the Fortran Language Standard (a very terse document that sets out everything the language provides) now extends to more than 600 pages. Instead, the book provided a general picture of how things work in Fortran, and showed the right way to go about tackling a problem. This investment in time has since paid itself back hundreds of times over.

The route to expert status in Maple was far more challenging. Its own help pages give a very comprehensive description of individual commands, but they are intended as a reference guide, and if it’s possible to become an expert using these alone, then I never discovered the correct order in which to read them. I found a number of books on Maple in the university library, but most were too basic to be useful, and others focused on particular applications. None seemed likely to give me the general picture — the feel for how things work — that would make Maple into the time-saving resource it was intended to be.

The picture became clearer after I taught Maple to students in three different courses. Nothing encourages learning better than the necessity to teach someone else! Investigating the problems that students experienced gave me new opportunities to properly understand Maple, and eventually the few remaining gaps were filled in by the Programming Guide. This is a complex document, similar in length to the Fortran Language Standard, but with more examples. Personally I would only recommend it to readers with experience of programming language specifications. Students now started to ask how I came to know so much about Maple, and whether there was a book that would teach them the same. Since no such book existed, I decided to write one myself. As the old adage goes, if you want something doing properly, do it yourself. The project soon began to evolve as I tried to set down everything that the majority of Maple users need to know. I’ve always hated books that skirt around important but difficult topics, so where before I might have used a dirty trick to circumnavigate a problem, now I felt compelled to research exactly what was going on, and to try to explain it in a simple, concise way. When the first draft was complete, I approached Cambridge University Press (CUP). The editor arranged for reviews by four anonymous referees**, and by Maplesoft’s own programming team. This led to several major improvements. My colleague, Dr Martyn Hughes, also deserves a mention for his efforts in reading and commenting on four different drafts. Meanwhile, Maplesoft continued to release new editions of their software, and the drafts had to be revised to keep up with these. The cover was created by one of CUP’s designers, with instructions that it should not look too ‘treeish’ — one might be surprised by the number of books that have been written about Maple syrup, and it would be a shame for Understanding Maple to be mixed up with these by potential readers browsing the internet. Then there were the minor details: how wide should the pages be? What font should be used? Should disk be spelled with a ‘c’ or a ‘k’? Could quotes from other sources be used without the threat of legal action over copyright infringement? One rights holder laughably tried to charge $200 for a fragment of text from one of their books. Needless to say, no greenbacks were forthcoming.

The resulting book is concise, with all the key concepts needed to gain an understanding of Maple, alongside numerous examples, packed into a mere 228 pages. It gives new users a solid introduction, and doesn’t avoid difficult topics. It isn’t perfect (in fact I have already started to list revisions that will be made if a second edition is published in the future) but I’ve seen very few problems that can’t be solved with the material it contains. Only time will tell if Understanding Maple will it create new experts. At the very least, I would certainly like to think it will make Maple far easier to grasp, and help new users to avoid some of the traps that caught me out many years ago.

 

Learn more about Understanding Maple, which is published by Cambridge University Press.

Typically, we publish a “Meet Your Developers” profile, where you can get an inside look at the lives of our developers. Today, we’re excited to bring you something a little different, a glimpse into the life of Maple Product Manager, Samir Khan.

Let's get right to it.

1. What do you do at Maplesoft?

I’m 50% of the product management team for Maple. I act as an interface between our developers, mathematicians, marketing, sales, and users.

I spend a lot of time speaking to current and potential customers – this is the most important part of my job.

At the beginning of each development cycle, I work with the developers to put together a list of proposed features. Then, during the year, I try to keep development on track to meet the proposed goals and provide continual feedback.

I also develop applications that demonstrate Maple’s functionality in new and different ways (most are on the Application Center).

2. What did you study in school?

I studied Chemical Engineering.

3. What area(s) of Maple are you currently focusing on in your development?

While I don’t do any direct development of Maple features, I sometimes prototype code as a proof of concept. The developers then look at me with a sense of disdain, tear my prototype apart, and rewrite my code from the ground up.

4. What’s the coolest feature of Maple that you’ve had a hand in developing?

While I generally don’t develop any production code, I’ve been responsible for driving the ThermophysicalData package forward

5. What do you like most about working at Maplesoft? How long have you worked here?

I’ve worked at Maplesoft since 2008. It’s a cliché, but I like the people first and foremost.

I also like the flexibility of my role. Within reason, I can devote part of my time doing things that I think will benefit the company. For example, I get to write lots of applications about subjects that interest me (usually thermodynamics or chemistry).

6. Favourite hobby?

I gave up all my hobbies when kids appeared on the scene. Before that, I wrote spreadsheets for financial modeling

Now, I like to do home science experiments with my son. Yesterday, I mixed yeast with hydrogen peroxide to demonstrate an exothermic reaction.

7. What do you like on your pizza?

Pineapple and mushrooms.

8. What’s your favourite movie?

I don’t really have a single favourite movie, but these movies that have the greatest impact on me over the last few years

  • Interstellar
  • Annihilation
  • Dunkirk
  • The Witch
  • Frozen (yes, really)

9. What skill would you love to learn? (That you haven’t already) Why?

I want to learn how to juggle to amuse my kids. However, I don’t have the hand-eye coordination to be any good

10. Who’s your favourite mathematician?

That’s a really dreary question.

Instead, I’ll answer two completely different questions.

  • My favorite kids TV show is Ben and Holly’s Little Kingdom
  • I usually listen to Slayer on the drive into work

 

Thanks Samir!

At Maplesoft, we are excited to be celebrating our 30th year of incorporation. This anniversary is a tremendous milestone for us. As a leading provider of mathematics-based software solutions for science, technology, engineering and mathematics (STEM), this longevity attests to our ability to grow along with changing market conditions, to continually enhance the quality of our offerings and strengthen our partnerships with industry leaders.

As a company, it is our goal to actively connect and partner with our users and industry leaders to advance STEM education and continue to revolutionize engineering design processes. When it comes to academics, we believe our partnerships and outreach initiatives help improve STEM education, develop and enhance digital learning tools and foster online education. To that end, Maplesoft is an Affiliate Member of the Fields Institute, Educational Outreach Champion of Perimeter Institute, and Technology Partner of the American Math Society’s “Who Wants to be a Mathematician” student competition. On the commercial side, we work closely with our commercial partners to seamlessly integrate our technology with complementary tools. Our relationships with prominent companies such as Rockwell Automation, B&R, Altair and more, allow us to continue leading this charge.

At Maplesoft, we work continuously to improve our technology offerings by developing new products and enhancing our existing technology. Maple 2018, the newest version of our flagship product Maple, offers new and improved features to benefit all users, no matter what they use Maple for. It provides an environment where students and instructors can enrich the classroom experience, researchers can accelerate their projects and engineers can refine their calculation management processes. Möbius, our online courseware platform, enables instructors to author rich content, explore important STEM concepts using engaging, interactive applications, visualize problems and solutions, and test students’ understanding by answering questions that are graded instantly.

On the engineering side, we are revolutionizing the engineering design process using Digital Twins, which are virtual machine designs created in MapleSim, Maplesoft’s modeling and simulation software. By taking a virtual approach to machine-level system integration, engineers can commission faster, earlier, and with less risk.

Maplesoft has come a long way since our humble beginnings as a research project at the University of Waterloo. Our website features a timeline that provides insights and information on our incredible journey. The company was built on a foundation of creativity and passion for mathematics and we have worked hard to preserve that legacy. The growth experienced over the past 30 years, along with the drive of our global employee and partner base, will ensure Maplesoft continues to be a driving force in the world of online education and design engineering long into the future.

We invite you to join us as we continue our journey towards new and exciting developments and innovations.

To demonstrate Maple 2018’s new Python connectivity, we wanted to integrate a large Python library. The result is the DeepLearning package - this offers an interface to a subset of the Tensorflow framework for machine learning.

I thought I’d share an application that demonstrates how the DeepLearning package can be used to recognize the numbers in images of handwritten digits.

The application employs a very small subset of the MNIST database of handwritten digits. Here’s a sample image for the digit 0.

This image can be represented as a matrix of pixel intensities.        

The application generates weights for each digit by training a two-layer neural network using multinomial logistic regression. When visualized, the weights for each digit might look like this.

Let’s say that we’re comparing an image of a handwritten digit to the weights for the digit 0. If a pixel with a high intensity lands in

  • an intensely red area, the evidence is high that the number in the image is 0
  • an intensely blue area, the evidence is low that the number in the image is 0

While this explanation is technically simplistic, the application offers more detail.

Get the application here

Today we are pleased to announce the release of Maple 2018.

For many people, today is just another day in March. It’s not like the release of a new version of a software product is a world-shaking event. But for us here at Maplesoft, these first few days after the latest version of Maple is released are always a bit more special. There’s always a nervous energy whenever we release Maple and everyone else gets to see what we’ve been pouring our efforts into for the past year.

I’m not going to start this post by calling the latest version of Maple “game-changing” or “cutting edge” or any other marketing friendly platitude. I’m well aware that the latest version of Maple isn’t going to change the world.

What I would say though is that with every new release of software comes an opportunity. Every new software release is an opportunity to re-evaluate how that software has evolved to better suit your needs and requirements. So… if you've been sitting on the sidelines and watching version after version go by, assuming that it won't affect you, that's wrong! There's a lot that you could be missing out on.

The way that these release announcements usually work is that we try to amaze and astound you with a long list of features. Don’t worry, I’ll get into that in a bit. But first I wanted to walk through a simple exercise of release arithmetic.

I’ll start with one of those basic truths that has always been hiding in plain sight. The build number # for Maple 2018 is 1298750. Here at Maplesoft, every time our developers make a change to Maple this build number goes up by 1. These changes are sometimes small and sometimes very big; they can be as small as fixing a documentation typo or they can constitute implementing a major feature spread across numerous files in our source tree.

I have come to look at these build numbers in a slightly different way. I look at build numbers as representing all of the small to large sized steps our developers take to get you from one version to the next (or put another way, how many steps behind you are if you are using the older versions). With that in mind, let’s do some quick math:

If you are using Maple 2017 (2017.0 was build # 1231047), there have been 1298750 – 1231047 = 67703 steps since that release (these numerous "steps" are what built the "long list" of features below). If you’re using Maple 2016 (#1113130) this number grows to 185620. And so it goes… Maple 2015 (#1022128) = 276622 steps, Maple 18 (#922027) = 376723, Maple 17 (#813473) = 485277, you get the idea. If you’re using a really old version of Maple – there’s a good chance that we have fixed up a bunch of stuff or added something that you might find interesting in the time since your last upgrade!

 

Every new release of Maple adds functionality that pushes Maple into new domains, rounds out existing packages, fills gaps, and addresses common user requests. Let's explore some additions:

 

Clickable Math - a.k.a. math that looks like math and can be interacted with using your mouse - has evolved. What was once a collection of operations found in the right-click or main menu items or in interactive smart-popups or in many additional dialogs, has been brought together and enhanced to form the new Context Panel.

We can summarize the Context Panel as follows: Enter an expression and relevant operations that you can apply to that expression appear in a panel on the right side of your screen. Easy, right? It's a great change that unlocks a large part of the Maple library for you.

The addition of the Context Panel is important. It represents a shift in the interaction model for Maple – you’ll see more and more interaction being driven through the context panel in future releases. Already, the changes for the Context Panel permeate through to various other parts of Maple too. You’ll see an example in the Units section below and here’s another for coding applications.

The Context Panel also gives you access to embedded component properties – this makes it much easier to modify parts of your application.

There’s much more we can say about the Context Panel but in the interest of keeping this post (somewhat) concise I’ll stop there. If you are interested and want to see more examples, watch this video.

 

Coding in Maple - For many of us, using the Maple coding language is fundamental; it's just what we do. Whether you write a lot of procedures, or modify the start-up code for your worksheet, or put a sequence of commands in a code edit region, or include a button or slider in your application, you’ll find yourself using Maple’s code editing tools.

For Code Edit Regions and the Maple Code Editor, there’s automatic command completion for packages, commands, and even file paths.

maplemint has been integrated into the Code Editor, providing code analysis while you write your code.

mint and maplemint have been unified and upgraded. If you’ve never heard of these before, these are tools for analysing your Maple code. They provide information on procedures, giving parameter naming conflicts, unreachable code, unused parameters or variables, and more. Mint is available for use with external text files and maplemint runs directly inside of Maple.

For more, I’ve got another video.

 

For many engineers and scientists, units are intrinsically linked with calculations. Here's something else in Maple 2018 that will improve your everyday experience – units are now supported in many core routines such as in numeric equation solving, integration, and optimization.

Here’s a quick example of using units in the int command with some thermophysical data:

We define an expression that gives the pressure of methane as a function of the specific volume V.

P := ThermophysicalData:-Property("pressure", "methane", "temperature" = 350*Unit('K'), "density" = 1/V):
-(int(P, V = 1.0*Unit('m'^3/'kg') .. .5*Unit('m'^3/'kg'), numeric));

You'll also find unit formatting in the Context Panel.

Near and dear to my heart, data analysts also have some occasion to rejoice. Maple 2018 finally adds an Interpolate command that supports irregular data! This is one of those items that users have been requesting for a long time and I'm very happy to say that it's finally here.

Furthering the data story, there are new sources for thermochemical data as well as updates to ensure that existing datasets for thermophysical data and scientific constants are up to date.

 

If you're interested in protecting your content in Maple, listen up:

You can now encrypt procedures; anyone can use your code, but they can't see the source!

You can also lock your Maple documents - effectively protecting them from accidental changes or other unintended modifications.

 

 

Of course, I won't leave mathematics out of this. As always, there’s a ton of new and updated stuff here.

There's a new computational geometry package. There are improvements across all fields of mathematics including group theory, graph theory, integration, differential equations and partial differential equations. And there's a ton of new work in Physics (many of you who have been following the Physics project will already know about these).

You can recreate some of the visualizations above as follows:

Here’s an example of the new VoronoiDiagram Command:

m := LinearAlgebra:-RandomMatrix(40, 2):
ComputationalGeometry:-VoronoiDiagram(m, showpoints, symbol = solidcircle, symbolsize = 7,colorregions=ColorTools:-GetPalette("Dalton"));

Here’s another change that I’ve seen mentioned several times on MaplePrimes – the ability to control the  border of arrows:

plots:-display(plottools:-arrow([0, 0], [2, 2], 0.5e-1, .2, .1, border = false, color = "DarkGrey", legend = "A+B"),
                       plottools:-arrow([0, 0], [1, 2], .15, .3, .15, border = false, color = "Crimson", legend = "A"),
                       plottools:-arrow([1, 2], [2, 2], .15, .3, .15, border = false, color = "CornflowerBlue", legend = "B"),
                   size = [600, 400]);

You can rotate Tickmarks in plots using the rotation option. Some plots, such as those in the TimeSeriesAnalysis package, use rotation by default.

ts := TimeSeriesAnalysis:-TimeSeries([7, 23, 21, 19, 13, 46, 42, 30, 31, 26, 19, 9, 16, 26, 17, 33, 31, 46, 42, 35, 45, 30, 11, 17, 23, 20, 15, 36, 31, 55, 49, 39, 36, 28, 12, 11, 21, 23, 27, 33, 36, 49, 42, 37, 33, 45, 12, 7, 23, 32, 25, 42, 27, 52, 50, 34, 41, 40, 16, 14], frequency = monthly, startdate = "2005-09");
TimeSeriesAnalysis:-SeasonalSubseriesPlot(ts, startingperiod = 9, seasonnames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], space = .25, size = [800, 400]);

 

I’ll also mention some updates to the Maple language – items that the readers of this forum will likely find useful.

Dates and Times – Maple 2018 adds new data structures that represent dates and times. There are numerous functions that work with dates and times, including fundamental operations such as date arithmetic and more advanced functionality for working with Calendars.

today := Date();

Year( today ), DayOfMonth( today ), Month( today );

Date arithmetic:

One_year_ago := today - 365*Unit(d);

 

Until - An optional until clause has been added to Maple's loop control structure.

Here's an example, the following code finds the next prime number after 37 and then terminates the loop.

n := 37;

do n := n+1 until

    isprime(n):

n;

As always with these posts, we can't cover everything. This post is really just the beginning of the story. I would love to spend another couple of pages describing the inner-workings of every single improvement to Maple 2018 for you; however I'd rather you just try these features yourself, so go ahead, get out there and try out Maple 2018 today. You won't be disappointed that you did.

First 11 12 13 14 15 16 17 Last Page 13 of 34