An Introduction To MATHEMATICA Kevin Perry SEAS / MECA About the MECA clusters The Hardware There are two public clusters of Silicon Graphics workstations here at the Multimedia Engineering Computation Atelier (MECA). Both rooms are open 24 hrs/ 7 days. - The Indys (E423) MIPS R4600 CPU chip, at 100 MHz. 1024x1280 pixel, 24-bit color display 32 Meg memory Audio/video hardware - The Personal IRISes (E417) MIPS R2000 CPU chip, at 36 MHz. 1024x1280 pixel, 24-bit color display 16 Meg memory The Software The SGI workstations use the X11 Windowing System. Here are some hints for getting started with navigating in this environment: - The mouse cursor MUST be inside the window you wish to type in. - Holding down the right mouse button always gives you a menu; when the cursor is over the background, you get the Window Manager Menu. - To logout, choose "Log Out" from the Window Manager Menu. Then answer "Yes" to the confirmation window that will appear. - Use the left mouse button on the edge of a window, to drag the window around. -Use the left mouse button on a scrollbar to scroll. "What is MATHEMATICA?" Background MATHEMATICA was originally created by Steven Wolfram. It is a product of Wolfram Research, Inc. Versions are available for most popular operating systems, including SGI, Sun, NeXT, Mac, DOS, and Windows. We are currently running release 2.2.2 Overview of uses MATHEMATICA is... - an arithmetic, symbolic and algebraic calculator - a language for developing transformation rules, to express general mathematical relationships - an interactive environment for numerical, symbolic and graphical exploration - a tool for preparing input to other programs, or to process output from other programs A Friendly Warning "Like cars and knives and most other useful things, symbolic manipulation systems in general, and MATHEMATICA in particular, are inherently dangerous and not for the reckless." Division of Labor MATHEMATICA is divided into two parts, the "kernel" and the "front-end". The front-end, also known as the Notebook Interface, is the graphical user interface. When you type in a command, the Notebook acts as your intermediary, and passes the commands to be evaluated on to the kernel. The Notebook handles formatting of text, and allows for un-evaluated text fields, and other nice things, all of which make documents such as this one possible! The kernel is where the mathematics really takes place. It may run on the same machine as the front-end, or on a different machine. Getting Started Sources of Help The first way to get help, is to use MATHEMATICA's online help facilities ( more about those later). Another excellent source of information is the book "Mathematica, A System for Doing Mathematics by Computer", by Steven Wolfram, published by Addison- Wesley. This book is highly recommended for anyone who wants to use MATHEMATICA seriously. It is available at the University Store. A copy of my lecture notes for this course, and pointers to some other useful information, are available via the World Wide Web, at: http://www.princeton.edu/~perry/math.html A short document about getting started with MATHEMATICA is available from the CIT Info Center, or MECA staff. Beginning To start MATHEMATICA, type "mathematica" at the UNIX prompt. % mathematica You may also specify the name of a file for it to load, if you have saved one from a previous session. % mathematica mywork.ma When the notebook window has opened on your screen, move the mouse cursor into the white input region, and enter your commands. To tell MATHEMATICA to evaluate a command, you must press the <Enter> key while holding down the <Shift> key. the first evaluation will take a while, because it must first start the MATHEMATICA kernel. By default, it will start a remote kernel on the machine ERNIE. More about the Notebook Interface Here's the point where we take a look at the menus provided by the notebook interface... Advanced Beginning To run a session where your terminal talks directly to the MATHEMATICA kernel, without the notebook interface, type "math" at the UNIX prompt. Note that this will only work on a machine which is licensed to run the kernel, e.g. phoenix or ernie. Also, if you wish to do graphics in this mode, you must make sure that your DISPLAY environment variable is set appropriately: phoenix% setenv DISPLAY picasso:0 phoenix% math When it is ready and waiting for input, you will see the MATHEMATICA prompt: In[1]:= Things You Can Do! You can do arithmetic: 32545 + 1237 27 * 10.3 You can work with exact numbers and fractions: 2^80 23453/102406 + 37821/332216 FactorInteger[390390] You can get approximate numerical results to any precision: N[23453/102406 + 37821/332216] N[Sqrt[2], 17] You can use complex numbers and special functions: (2 + 3 I )^2 Conjugate[2 + 3 I] BesselJ[1, 2.0*Pi] ...and much, much more! Syntax and Grammar Naming The names of all built-in MATHEMATICA functions begin with capital letters. They tend not to abbreviate names, beyond what is normal mathematical practice, and multi-word names have internal capitalization. Some examples are: Sin, Log, Sqrt, Random, Eigenvalues, FactorInteger. Arithmetic addition: 2 + 2 subtraction: 4 - 1 multiplication: 3 * 2 ...and also: 3 2 division: 15/2 exponentiation: 4^2 factorial: 4! Grammar a list: { 1, 2, 3, 4 } a function: f[x, y] a list element: v[[1]] parentheses for grouping: 2*(3 + 5) a rule: x -> 5 a definition: f[x_] := 2 x + 5 an assignment: x = 42 Special Symbols help: ? verbose help: ?? help wildcards: *, @ some examples... ?Sqrt ??Sqrt ?S@@ ?S* History substitution (re-using previous output): % ...for example: 3 * 7 5 * % 6 * %% 7 * %1 Advanced Function Shorthand Postfix: x // f ReplaceAll: (x^2 + 3 x) /. x -> (a+b) Map: Factorial /@ {1, 2, 3} Apply: Times @@ a+b+c (more about these later!...) Common Constants Some of the most useful mathematical constants are built-in: Pi E GoldenRatio EulerGamma Infinity ComplexInfinity All About Lists We use lists in MATHEMATICA to represent such things as vectors, arrays, matrices, sets, and so forth. For example, here is a 3-vector: v = { 1, 4, 2 } ...and a 2x2 matrix m = { { 1, 2 }, { 3, 4 } } List indices start at 1, not 0. Indexing is done thus: v[[1]] m[[2]][[2]] ...or... m[[2,2]] Here are some simple ways to create a list: Range[10] Array[Factorial, 6] Table[x^2, {x, 4, 12}] This last example has as its second argument, an "iterator list", which defines the iterator variable ("x"), and its range; you can specify either a maximum; or a min and max; or min, max, and step size. These three iterator lists are equivalent: {x, 12}, {x, 1, 12}, {x, 1, 12, 1}. A matrix is just a list of lists, so we can create one thus: Table[Table[x^2-y, {x, 3}], {y, 0.0, 2.0, 0.5}] Here are some simple list operations: mylist = Range[13] Drop[mylist, 3] Take[mylist, 3] Append[mylist, 3] Prepend[mylist, 3] Partition[mylist, 3] Basic Calculations Algebra define a polynomial expression: poly = (1 - x^2)(2 + 3x) ...and perform some manipulations on it: Expand[poly] Factor[poly] solns = Solve[poly == 0, x] poly /. x -> 2 poly /. solns[[1]] Coefficient[Expand[poly], x^2] Here are some more useful algebraic manipulations: Simplify[x^3 + 3x^2 + 3x + 1] quot = Together[1/(1+x) + 2/(1-x)] Apart[quot] Numerator[quot] Denominator[quot] More about solving equations: Solve[x^2 == 1, x] Solve[{x + 2y == 3, 2x - y == 5}, {x, y}] Solve[{x + 2y == 3, 2x - y == 5}, x, y] Solve[2 x^2 == 3, x] NSolve[2 x^2 == 3, x] FindRoot[2 x^2 == 3, {x, 3}] Solve[2 x^2 == 3 && Modulus == 7, x] Calculus Here is an expression: expr = 2 + 3x + x^2 - Log[x] We can differentiate it... D[expr, x] D[expr, x, x] Integrate it... Integrate[expr, x] Integrate[expr, {x, 0, 1}] NIntegrate[expr, {x, 0, 1}] ... but be careful about precision and accuracy measurements for numerical integration NIntegrate[expr, {x, 0, 1}, WorkingPrecision->25, AccuracyGoal->20] Options[NIntegrate] Infinite integration bounds are done like this: Integrate[Exp[-x], {x, 0, Infinity}] We can also ask for the total differential of a multi-variable expression: Dt[x^2 + y^2, x] Differential Equations The derivative of an unknown function, y, can be represented by: y' Thus , we can solve differential equations like this: DSolve[y'[x] + y[x] == 1, y[x], x] Or, for a functional representation of y: DSolve[y'[x] + y[x] == 1, y, x] Or use numerical methods: NDSolve[{y'[x] == y[x], y[0] == 1}, y, {x,0,2}] Other Common Tasks ...such as limits, residues, constrained optimization, matrices: Limit[Sin[x]/x, x->0] Limit[1/x, x->0, Direction->1] Residue[1/x, {x, 0}] ConstrainedMax[x - y, {x < 2y, x < 4}, {x, y}] ConstrainedMin[x - y, {x > 3y, x > 2}, {x, y}] mat = {{1, 2},{3, 4}} Det[mat] Eigenvalues[mat] Eigenvectors[mat] "My Polynomial"] SetOptions[Plot, PlotRange->All] Options[Plot] What is wrong with this command? Plot[{poly, D[poly, x]}, {x, -5, 5}] The Plot command "Holds" its first argument, for delayed evaluation. Sometimes, as above, this is not the desired behavior. In this case, we must use "Evaluate" to force early evaluation of the argument. This behavior of Plot is controlled by its attributes: Attributes[Plot] Here are two functions plotted on the same graph: Plot[{Sin[x], Cos[x]}, {x, 0, 2Pi}] Here are four separate graphs: plots = {Plot[Sin[x], {x, 0, Pi}], Plot[Cos[x], {x, 0, Pi}], Plot[Tan[x], {x, 0, Pi}], Plot[Cot[x], {x, 0, Pi}]} Here they are arranged together in a 2x2 array: Show[GraphicsArray[Partition[plots, 2]]] Printing Graphs Graphics may be sent directly to the printer, or saved to a PostScript format file: myplot = Plot[poly, {x, -4, 4}] LaserPrint[myplot] PSFile["myplot.ps", myplot] Or, a notebook cell may be selected, and printed using the File/Print Selection menu item. The notebook printing mechanism allows you to change the printer options. To find out the name of the default printer, use the command: Environment["PRINTER"] Plotting Data Lists of data may be read in from files, or created inside MATHEMATICA. Here' s an example data set: mylist = Array[Prime, 50] Such a list may be plotted with the ListPlot command: ptgraph = ListPlot[mylist] lngraph = ListPlot[mylist, PlotJoined->True, Prolog->Thickness[0]] Here are the two versions of the graph, drawn together: Show[ptgraph, lngraph] We can find a quadratic fit to this data: fitpoly[x_] = Fit[mylist, {1, x, x^2}, x] ...and graph the polynomial against the data: Show[Plot[fitpoly[x], {x, 0, 26}, PlotRange->All, Prolog->Thickness[0]], ListPlot[mylist]] we can also make a list of (x,y) pairs, and graph that: xy = Table[{j, j^2}, {j, -3, 3, .2}] ListPlot[xy] 3D Plotting The basic 3D plotting command is "Plot3D": p3d = Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 2.5}] Show[p3d, Mesh->False] Options[Plot3D] There is also a list version, for plotting data: z = Table[2x - y^2, {x, 0, 6, .5}, {y, 0, 6, .5}]; ListPlot3D[z] There are also functions to make contour plots and density plots; here are some examples: ContourPlot[x Sin[y], {x, 0, 3}, {y, 0, 3}] DensityPlot[x Sin[y], {x, 0, 3}, {y, 0, 3}] ListContourPlot[z] ListDensityPlot[z] Input and Output Reading, Writing Notebooks Use the Open, Save and Save As items in the File menu on the menu bar. To read a Notebook file created on a different type of machine, use the Open Special item, and select "Ignore .mb auxiliary file". Reading Command Files To read and execute a MATHEMATICA command file (NOT a Notebook file): <<myfile.m Handling Data (1) The simplest way to output data is in MATHEMATICA format, using the Put operator. For example: mylist = Range[20] mylist >> list.m We can examine the contents of this file by doing: !!junk.m This List can then be loaded back in using the Get operator: newlist = <<list.m Handling Data (2) Another approach is to write out individual numbers, one per line. This format is easier for other applications to read, since they don't have to understand MATHEMATICA syntax. For instance, given a flat list, like "mylist" above, we can: Apply[Put, Append[mylist, "out.data"]] more generally, you could force the list to be flat: Apply[Put, Append[Flatten[mylist], "out.data"]] Or, you could design your own little program to output exactly the data you want to store, using the PutAppend operator: For[ i=1, i<=Length[mylist], i++, mylist[[i]] >>> "out.data"] Each of these methods produces the same file format: !!out.data This file can be read back into a MATHEMATICA list easily: newlist = ReadList["out.data", Number] We can specify other list formats, e.g. read it as a list of pairs of numbers: newlist = ReadList["out.data", {Number, Number}] Advanced Topic: MathLink It is also possible (though messy) to write a C program which interfaces with MATHEMATICA directly. The program must be written according to the MathLink specifications, and compiled with the MathLink library module, available in the MATHEMATICA application directory. There is support both for programs which start a copy of the kernel, and send it expressions to evaluate, and for programs which can be called by MATHEMATICA, to perform calculations not easily implemented inside MATHEMATICA. See the appropriate manuals for details. Contexts and Packages What is a Context? Just as files in the UNIX file system are organized into a hierarchy of directories, MATHEMATICA commands are organized into a hierarchy of Contexts. A Context is simply a named collection of MATHEMATICA commands. Context names are marked by a trailing `. When you start a session, there are typically two active Contexts: the System` context holds all the built-in commands, and the Global` context holds any definitions that you make. The list of currently active contexts is stored in the variable $ContextPath. $ContextPath What is a Package? A Package is a special type of Context, which is used to encapsulate a group of closely related commands. Package Contexts provide automated loading of dependent Packages. MATHEMATICA provides a large number of useful Packages, which you can load and use. Loading one of these Package files into your MATHEMATICA session will define a new Context, named after the Package, add that context to the $ ContextPath, and load some definitions into it. For example, one of the available Packages contains functions for working with permutations. Let's load it: <<DiscreteMath/Permutations.m Notice the $ContextPath has changed: $ContextPath What functions has it defined for us? ?DiscreteMath`Permutations`* Here is a list of all the available Packages: Algebra/CountRoots.m Algebra/Master.m Algebra/ReIm.m Algebra/SymbolicSum.m Algebra/Trigonometry.m Calculus/FourierTransform.m Calculus/LaplaceTransform.m Calculus/Limit.m Calculus/Master.m Calculus/Pade.m Calculus/VectorAnalysis.m DiscreteMath/CombinatorialFunctions.m DiscreteMath/CombinatorialSimplification.m DiscreteMath/Combinatorica.m DiscreteMath/ComputationalGeometry.m DiscreteMath/Master.m DiscreteMath/Permutations.m DiscreteMath/RSolve.m DiscreteMath/Tree.m Examples/CellularAutomata.m Examples/Collatz.m Examples/FileBrowse.m Examples/IntegerRoots.m Examples/Life.m Examples/OneLiners.m Examples/OptionUtilities.m Geometry/Master.m Geometry/Polytopes.m Geometry/Rotations.m Graphics/Animation.m Graphics/ArgColors.m Graphics/Colors.m Graphics/ComplexMap.m Graphics/FilledPlot.m Graphics/Graphics.m Graphics/Graphics3D.m Graphics/ImplicitPlot.m Graphics/Legend.m Graphics/Master.m Graphics/MultipleListPlot.m Graphics/ParametricPlot3D.m Graphics/PlotField.m Graphics/PlotField3D.m Graphics/Polyhedra.m Graphics/Shapes.m Graphics/Spline.m Graphics/SurfaceOfRevolution.m Graphics/ThreeScript.m LinearAlgebra/Cholesky.m LinearAlgebra/CrossProduct.m LinearAlgebra/GaussianElimination.m LinearAlgebra/Master.m LinearAlgebra/MatrixManipulation.m LinearAlgebra/Orthogonalization.m LinearAlgebra/Tridiagonal.m Miscellaneous/Calendar.m Miscellaneous/ChemicalElements.m Miscellaneous/CityData.m Miscellaneous/Geodesy.m Miscellaneous/Master.m Miscellaneous/PhysicalConstants.m Miscellaneous/SIUnits.m Miscellaneous/Units.m Miscellaneous/WorldData.m Miscellaneous/WorldNames.m Miscellaneous/WorldPlot.m NumberTheory/ContinuedFractions.m NumberTheory/FactorIntegerECM.m NumberTheory/Master.m NumberTheory/NumberTheoryFunctions.m NumberTheory/PrimeQ.m NumberTheory/Ramanujan.m NumberTheory/Rationalize.m NumberTheory/Recognize.m NumericalMath/Approximations.m NumericalMath/Butcher.m NumericalMath/CauchyPrincipalValue.m NumericalMath/ComputerArithmetic.m NumericalMath/GaussianQuadrature.m NumericalMath/IntervalArithmetic.m NumericalMath/ListIntegrate.m NumericalMath/Master.m NumericalMath/NLimit.m NumericalMath/NewtonCotes.m NumericalMath/PolynomialFit.m ProgrammingExamples/AlgExp.m ProgrammingExamples/ArgColors.m ProgrammingExamples/Atoms.m ProgrammingExamples/BookPictures.m ProgrammingExamples/Collatz.m ProgrammingExamples/ComplexMap.m ProgrammingExamples/ComplexTest.m ProgrammingExamples/Constants.m ProgrammingExamples/ExpandBoth.m ProgrammingExamples/Fibonacci1.m ProgrammingExamples/FilterOptions.m ProgrammingExamples/GetNumber.m ProgrammingExamples/MakeFunctions.m ProgrammingExamples/MyReadList.m ProgrammingExamples/Newton.m ProgrammingExamples/Numerical.m ProgrammingExamples/OddEvenRules.m ProgrammingExamples/OptionUse.m ProgrammingExamples/ParametricPlot3D.m ProgrammingExamples/PrimePi.m ProgrammingExamples/PrintTime.m ProgrammingExamples/RandomWalk.m ProgrammingExamples/ReadLoop1.m ProgrammingExamples/RungeKutta.m ProgrammingExamples/SessionLog.m ProgrammingExamples/ShowTime.m ProgrammingExamples/Skeleton.m ProgrammingExamples/SphericalCurve.m ProgrammingExamples/Struve.m ProgrammingExamples/SwinnertonDyer.m ProgrammingExamples/Tensors.m ProgrammingExamples/Transcript.m ProgrammingExamples/TrigDefine.m ProgrammingExamples/TrigSimplification.m ProgrammingExamples/Until.m ProgrammingExamples/VectorCalculus.m ProgrammingExamples/WrapHold.m Statistics/ConfidenceIntervals.m Statistics/ContinuousDistributions.m Statistics/DataManipulation.m Statistics/DescriptiveStatistics.m Statistics/DiscreteDistributions.m Statistics/HypothesisTests.m Statistics/InverseStatisticalFunctions.m Statistics/LinearRegression.m Statistics/Master.m Statistics/MovingAverage.m Statistics/NormalDistribution.m Utilities/DXF.m Utilities/FilterOptions.m Utilities/Language.m Utilities/Master.m Utilities/ShowTime.m Fancy Graphics Animated Graphs First, make a bunch of plots: Table[Plot[Sin[t x], {x, 0, 2Pi}], {t, 1, 5, .2}] ...then select all the plots, and choose the "Graph/Animate Selected" menu item. Interactive 3D graphics Before trying this, you need to issue the command: xhost localhost at the UNIX prompt on your workstation. It only works on SGI machines. Live[Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 2}]] Another way to do this is: ThreeScript["file.3ps", %] ...and then, at the UNIX prompt, type live file.3ps Drawing Shapes We can make pictures of geometric shapes by building up lists of MATHEMATICA graphics primitives. Some of these primitives are, for example: Point[], Line[ ], Polygon[], Rectangle[], Circle, Disk[]. One packages that utilizes these is the Shapes package: <<Graphics/Shapes.m ?Graphics`Shapes`* Let's draw two interlocking toruses, using this package: t1 = Torus[]; t2 = RotateShape[Torus[], Pi/2, Pi/2, 0]; t3 = TranslateShape[t2, {1, 0, 0}]; Show[Graphics3D[{t1, t3}]] Drawing a Helix Here we use the ParametricPlot3D command to draw a helical curve in 3-space: helix[t_, w_] := {t, Sin[w t], Cos[w t]} ParametricPlot3D[Evaluate[helix[x, 4], {x, 0, 10}]] Defining Transformations A Simple Function Functions are defined by transformation rules, which map a list of arguments to an output value. We've already seen expressions, such as: expr = 3 x + 7 Here is a function representing the same expression: f[x_] := 3 x + 7 Note the "x_", (called "x-blank") which represents any expression, and names it x; and the delayed-evaluation operator, ":=", which leaves the right-hand side in its symbolic form, instead of evaluating it immediately (which might cause a value to be substituted for x). We can now evaluate this function in various ways: f[0] f[5] f[t] f[a+b] We can define a piecewise-linear function, by overriding this definition for some values of x, using a Conditional operator: f[x_] := x + 9 /; x > 1 f[5] Plot[f[x], {x, -5, 5}] The Factorial Function Here is a very simplistic definition of the factorial function. We give it an explicit value at 0, and define the value for x recursively in terms of x-1. Since the right-hand side of the first line is a constant, there's no need to use the delayed-evaluation operator. fac[0] = 1 fac[x_] := x*fac[x-1] The major problem with this is that for any argument that is not a positive integer, it dies an ugly death: fac[5] fac[4.2] fac[-3] fac[a] Here is a better definition of the factorial function. It relies on a Pattern object which matches only integer arguments and a Conditional, to restrict the domain of the recursive definition. factorial[0] = 1 factorial[x_Integer] := x*factorial[x-1] /; x > 0 We can extend this definition to cover all integers, defining it in terms of the Euler Gamma function: factorial[x_Integer] := Gamma[x+1] /; x < 0 We can also allow for real-number values: factorial[x_Real] := Gamma[x+1] Also, Patterns can be built to match more complicated expressions. For instance, to write a function ExponentOf, which returns the exponent part of an expression, we could define: ExponentOf[_^p_] := p ExponentOf[_] := 1 Programming Concepts Control Structures MATHEMATICA has functions to perform all of the usual program control operations needed for procedural programming. Note that these are actual functions, not special keywords. Do [ expression, {iterator, min, max} ] Do[Print[i!], {i, 2, 10}] For [ init_expr, test_expr, iterate_expr, body_expr ] For[i = 2, i < 10, i++, Print[i!]] If [ test_expr, if_true, if_false, if_neither ] abs[x_] := If[x < 0, -x, x, "x isn't a number"] Which[test, value, test, value, ... ] signum[x_] := Which[x < 0, -1, x > 0, 1, True, 0] A Simple Program As an example, let's say we wanted to build a table of primes. One way to tell if a number is prime, is to examine the EulerPhi function. Here is a short program that builds a list of primes less than some specified number: primes[max_] := Module[ {t={}, j}, For[j=2, j <= max, j++, If[EulerPhi[j] == j-1, AppendTo[t, j]] ]; Return[t] ] However, a more functional approach is usually more efficient. We could re- code this as: primes[max_] := Flatten[Position[Map[ Function[j, EulerPhi[j]==j-1], Range[max]], True]] This uses the "pure function" operator, Function, which takes a symbol (or list of symbols) to use as formal parameters, and a function body expression in terms of the formal parameters. As an example, we could write the squaring function as a pure function like this: Function[x, x^2] and use it to evaluate 42^2 like this: Function[x, x^2][42] This is useful for defining inline functions for use with such operators as Map and Apply, as in the above "primes" example. Advanced Examples Recommended Reading The book "Programming in Mathematica", by Roman Maeder, published by Addison- Wesley, is full of useful examples and programming tips, for getting the most out of Mathematica. Example Programming Techniques The Run-Length Encoding Problem As an example of some advanced programming techniques in MATHEMATICA, let's examine some solutions of the Run-Length Encoding problem. These solutions were written by various people, as entries in a competition to create "the most elegant solution" to this problem, at a MATHEMATICA conference, a few years ago. Note that none of them uses a traditional procedural programming model. Procedural programming is generally the least efficient approach in MATHEMATICA. The problem: create a program which takes an arbitrary list of integers as input, and produces a new list, which consists of {value, run-length} pairs describing the given input string. This is known as Run-Length Encoding, or RLE Compression. For example, the imput string { 7, 8, 8, 9, 9, 9, 9, 5, 5, 5, 5, 9, 9, 9 } should produce the output string {{ 7, 1 }, { 8, 2 }, { 9, 4 }, { 5, 4 }, { 9, 3 }} Here's an input cell with that data, to use as a test, or make up your own... data = { 7, 8, 8, 9, 9, 9, 9, 5, 5, 5, 5, 9, 9, 9 } Example 1: Syntactic Method encode1[{r___, w:(x_)..}] := Append[encode[{r}], {x, Length[{w}]} encode1[{}] := {} encode1[data] Example 2: Algebraic Method SetAttributes[iMul, Flat] iMul[{a_, m_}, {a_, n_}] := iMul[{a, m+n}] encode2[x_] := List @@ iMul @@ ({#,1}&/@x) encode2[data] Example 3: Replacement Rule Method encode3[s_] := {s,{}} //. { {{x_,t___}, {h___,{x_y_}}} -> {{t},{h,{x,y+1}}}, {{x_,t___}, {h___}} -> {{t},{h,{x,1}}}, {{},{h___}} -> {h} } encode3[data] Example 4: Functional Method encode4[x_] := (Transpose[{x[[#]], #-Drop[Prepend[#,0],-1]}])&[ Flatten[Append[Position [((Apply[Unequal,#])& /@ Partition[x,2,1]), True, Length[x]],1] ] encode4[{}] := {} encode4[data]