Applications, Examples and Libraries

Share your work here

We produce only one rotation of the cube by the angle Pi/2, and then repeat it at the following points, changing the colors of the faces in turn. And so the illusion is created that the cube is rolling along a straight line without slipping.
(Just a picture without any sense.)

Summary:Hough transform is a feature extraction algorithm widely used in digital image analysis. It identifies objects with specified shapes by letting all edge pixels in the image “vote” and extract candidates with the highest votes. The classical Hough transform is associated with the identification of straight lines, but with some modification, the algorithm can be used to detect objects of arbitrary shapes (usually circles, ellipses) in an image. Therefore, Hough transform has various applications in the field of computer vision. Samir and I implemented Hough transform to detect straight lines and circles in real world images and the results are below:

You can access the applications here for more details and try the algorithm on your own image!

Line Detection with Hough Transform

Circle Detection with Hough Transform

For people who want a bit more of the theory behind:

The voting procedure in Hough transform starts with an edge detector (we used the sobel edge detector in the applications). After locating all the edge pixels, the program will iterate through each of the pixels and record their “votes”. It is important to address that the voting procedure is completed in parameter space. For example, a straight line is usually in the form of y = a*x+b, the parameter space will be in terms of a and b. Hence y=2*x + 3 will be a point (2,3)  in the a-b space. However, notice that we cannot represent vertical lines with this system; it would take infinite memory to store a vertical line. Thus we use the polar coordinates system x*cos(θ) + y*sin(θ) - p = 0 instead, resulting in a θ -p space. Note that an image pixel (x1,y1) is represented by the intersection of all lines that satisfy x1*cos(θ) + y1*sin(θ) - p = 0, which in θ-p space is denoted as a sinusoidal curve. Hence the intersection of two different sinusoidal curves in θ-p space is essentially a unique, straight line that passes through two different image pixels. An intersection of 500 votes means that specific line passes through 500 edge pixels, implying that it is likely a solid contour line in the original image. In this way, by converting all edge pixels to sinusoidal curves in θ-p space, the algorithm is letting all pixels “vote”. In order to record the sinusoidal curves, we need an accumulator of θ * p dimensions. In the line detection application we used a matrix such that <= θ <= 180 and -sqrt(r2 +c2 ) <= p <= sqrt(r2 +c2 ), where r and c are the height (rows) and width (columns) of the image.

The voting procedure for circle detection is similar; the difference is in how we construct the accumulator to accommodate different parametrization for circles. Notice that a circle has three essential pieces of information, the x,y coordinates of centre and the radius. This suggests that our accumulator might have to be in three dimensions. In practice, circular Hough transform is usually performed with known or estimated radius, when the radius is not known, the most straightforward solution is indeed to test a range of possible radii with a 3-dimensional accumulator. However, this might be quite expensive, especially for images with high level of details.

Feel free to leave a comment if you have any question  :)  

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.

Allow me to introduce the Pauli Algebra package for Maple. This package implements the Clifford Algebra of Physical Space Cl3 through the use of complex paravectors. The syntax of the package is similar to the notation popularized by the work of Dr. William E. Baylis. For more information, check out the Wikipedia entry on Paravectors and the APS workbook available on Dr. Baylis' website


To install the Pauli Algebra package while in a Maple session, type



Alternatively, you can find the Pauli Algebra package in the MapleCloud, and choose the install button on the far right.


Upon installation, several help files become available in Maple Help to assist you with the syntax.


As you will see in the Pauli.mpl source code of the package workbook, a number of Maple functions have been overloaded to handle the package's Paravector datatype. If you wish to overload additional Maple functions, let me know, and I'll include them in future updates.


I'll sign off by attaching a Maple worksheet/pdf containing some examples.




These files contain the kinematics and dynamics of the solid using a new technique (ALT + ENTER) to visualize the results online and thus save space in our Maple worksheet. Seen from a relative approach. For engineering students. In Spanish.  (Intro)

Lenin Araujo Castillo

Ambassador of Maple

Recently I looked through an interesting book D. Wells "The Penquin book of Curious and Interesting Geometry" and came across this result, which I did not know about before: starting with a given quadrilateral , construct a square on each side. Van Aubel's theorem states that the two line segments between the centers of opposite squares are of equal lengths and are at right angles to one another. See the picture below:


It is interesting that this is true not only for a convex quadrilateral, but for arbitrary one and even self-intersecting one. This post is devoted to proving this result in Maple. The proof was very short and simple. Note that the coordinates of points are given not by lists, but by vectors. This is convenient when using  LinearAlgebra:-DotProduct  and  LinearAlgebra:-Norm  commands.

The code of the proof (the notation of the points on the picture coincide with their names in the code):

assign(seq(P||i=<x[i],y[i]>, i=1..4)):
assign(seq(Q||i=(P||i+P||(i+1))/2+<0,1; -1,0>.(P||(i+1)-P||i)/2, i=1..4)):
expand(DotProduct((Q||3-Q||1),(Q||4-Q||2), conjugate=false));
is(Norm(Q||3-Q||1, 2)=Norm(Q||4-Q||2, 2));

The output:


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.


For Maple 2018.1, there are improvements in pdsolve's ability to solve PDE with boundary and initial conditions. This is work done together with E.S. Cheb-Terrab. The improvements include an extended ability to solve problems involving non-homogeneous PDE and/or non-homogeneous boundary and initial conditions, as well as improved simplification of solutions and better handling of functions such as piecewise in the arguments and in the processing of solutions. This is also an ongoing project, with updates being distributed regularly within the Physics Updates.

Solving more problems involving non-homogeneous PDE and/or non-homogeneous boundary and initial conditions



Example 1: Pinchover and Rubinstein's exercise 6.17: we have a non-homogenous PDE and boundary and initial conditions that are also non-homogeneous:

pde__1 := diff(u(x, t), t)-(diff(u(x, t), x, x)) = 1+x*cos(t)
iv__1 := (D[1](u))(0, t) = sin(t), (D[1](u))(1, t) = sin(t), u(x, 0) = 1+cos(2*Pi*x)

pdsolve([pde__1, iv__1])

u(x, t) = 1+cos(2*Pi*x)*exp(-4*Pi^2*t)+t+x*sin(t)


How we solve the problem, step by step:



Example 2: the PDE is homogeneous but the boundary conditions are not. We solve the problem through the same process, which means we end up solving a nonhomogeneous pde with homogeneous BC as an intermediate step:

pde__2 := diff(u(x, t), t) = 13*(diff(u(x, t), x, x))
iv__2 := (D[1](u))(0, t) = 0, (D[1](u))(1, t) = 1, u(x, 0) = (1/2)*x^2+x

pdsolve([pde__2, iv__2])

u(x, t) = 1/2+Sum(2*(-1+(-1)^n)*cos(n*Pi*x)*exp(-13*Pi^2*n^2*t)/(Pi^2*n^2), n = 1 .. infinity)+13*t+(1/2)*x^2


How we solve the problem, step by step:



Example 3: a wave PDE with a source that does not depend on time:

pde__3 := (diff(u(x, t), x, x))*a^2+1 = diff(u(x, t), t, t)
iv__3 := u(0, t) = 0, u(L, t) = 0, u(x, 0) = f(x), (D[2](u))(x, 0) = g(x)

`assuming`([pdsolve([pde__3, iv__3])], [L > 0])

u(x, t) = (1/2)*(2*(Sum(sin(n*Pi*x/L)*(2*L*(Int(sin(n*Pi*x/L)*g(x), x = 0 .. L))*sin(a*Pi*t*n/L)*a-Pi*(Int(sin(n*Pi*x/L)*(-2*f(x)*a^2+L*x-x^2), x = 0 .. L))*cos(a*Pi*t*n/L)*n)/(Pi*n*a^2*L), n = 1 .. infinity))*a^2+L*x-x^2)/a^2


How we solve the problem, step by step:



Example 4: Pinchover and Rubinstein's exercise 6.23 - we have a non-homogenous PDE and initial condition:

pde__4 := diff(u(x, t), t)-(diff(u(x, t), x, x)) = g(x, t)
iv__4 := (D[1](u))(0, t) = 0, (D[1](u))(1, t) = 0, u(x, 0) = f(x)

pdsolve([pde__4, iv__4], u(x, t))

u(x, t) = Int(f(tau1), tau1 = 0 .. 1)+Sum(2*(Int(f(tau1)*cos(n*Pi*tau1), tau1 = 0 .. 1))*cos(n*Pi*x)*exp(-Pi^2*n^2*t), n = 1 .. infinity)+Int(Int(g(x, tau1), x = 0 .. 1)+Sum(2*(Int(g(x, tau1)*cos(n1*Pi*x), x = 0 .. 1))*cos(n1*Pi*x)*exp(-Pi^2*n1^2*(t-tau1)), n1 = 1 .. infinity), tau1 = 0 .. t)


If we now make the functions f and g into specific mappings, we can compare pdsolve's solutions to the general and specific problems:

f := proc (x) options operator, arrow; 3*cos(42*x*Pi) end proc
g := proc (x, t) options operator, arrow; exp(3*t)*cos(17*x*Pi) end proc


Here is what pdsolve's solution to the general problem looks like when taking into account the new values of f(x) and g(x,t):

value(simplify(evalindets(u(x, t) = Int(f(tau1), tau1 = 0 .. 1)+Sum(2*(Int(f(tau1)*cos(n*Pi*tau1), tau1 = 0 .. 1))*cos(n*Pi*x)*exp(-Pi^2*n^2*t), n = 1 .. infinity)+Int(Int(g(x, tau1), x = 0 .. 1)+Sum(2*(Int(g(x, tau1)*cos(n1*Pi*x), x = 0 .. 1))*cos(n1*Pi*x)*exp(-Pi^2*n1^2*(t-tau1)), n1 = 1 .. infinity), tau1 = 0 .. t), specfunc(Int), proc (u) options operator, arrow; `PDEtools/int`(op(u), AllSolutions) end proc)))

u(x, t) = 3*cos(42*Pi*x)*exp(-1764*Pi^2*t)+cos(Pi*x)*(65536*cos(Pi*x)^16-278528*cos(Pi*x)^14+487424*cos(Pi*x)^12-452608*cos(Pi*x)^10+239360*cos(Pi*x)^8-71808*cos(Pi*x)^6+11424*cos(Pi*x)^4-816*cos(Pi*x)^2+17)*(exp(289*Pi^2*t+3*t)-1)*exp(-289*Pi^2*t)/(289*Pi^2+3)



Here is pdsolve's solution to the specific problem:

pdsolve([pde__4, iv__4], u(x, t))

u(x, t) = ((867*Pi^2+9)*cos(42*Pi*x)*exp(-1764*Pi^2*t)+cos(17*Pi*x)*(exp(3*t)-exp(-289*Pi^2*t)))/(289*Pi^2+3)



And the two solutions are equal:

simplify(combine((u(x, t) = 3*cos(42*x*Pi)*exp(-1764*Pi^2*t)+cos(x*Pi)*(65536*cos(x*Pi)^16-278528*cos(x*Pi)^14+487424*cos(x*Pi)^12-452608*cos(x*Pi)^10+239360*cos(x*Pi)^8-71808*cos(x*Pi)^6+11424*cos(x*Pi)^4-816*cos(x*Pi)^2+17)*(exp(289*Pi^2*t+3*t)-1)*exp(-289*Pi^2*t)/(289*Pi^2+3))-(u(x, t) = ((867*Pi^2+9)*cos(42*x*Pi)*exp(-1764*Pi^2*t)+cos(17*x*Pi)*(exp(3*t)-exp(-289*Pi^2*t)))/(289*Pi^2+3)), trig))

0 = 0


f := 'f'; g := 'g'


Improved simplification in integrals, piecewise functions, and sums in the solutions returned by pdsolve



Example 1: exercise 6.21 from Pinchover and Rubinstein is a non-homogeneous heat problem. Its solution used to include unevaluated integrals and sums, but is now returned in a significantly simpler format.

pde__5 := diff(u(x, t), t)-(diff(u(x, t), x, x)) = t*cos(2001*x)
iv__5 := (D[1](u))(0, t) = 0, (D[1](u))(Pi, t) = 0, u(x, 0) = Pi*cos(2*x)

pdsolve([pde__5, iv__5])

u(x, t) = (1/16032024008001)*(4004001*t+exp(-4004001*t)-1)*cos(2001*x)+Pi*cos(2*x)*exp(-4*t)


pdetest(%, [pde__5, iv__5])

[0, 0, 0, 0]



Example 2: example 6.46 from Pinchover and Rubinstein is a non-homogeneous heat equation with non-homogeneous boundary and initial conditions. Its solution used to involve two separate sums with unevaluated integrals, but is now returned with only one sum and unevaluated integral.

pde__6 := diff(u(x, t), t)-(diff(u(x, t), x, x)) = exp(-t)*sin(3*x)
iv__6 := u(0, t) = 0, u(Pi, t) = 1, u(x, 0) = phi(x)

pdsolve([pde__6, iv__6], u(x, t))

u(x, t) = (1/8)*(8*(Sum(2*(Int(-(-phi(x)*Pi+x)*sin(n*x), x = 0 .. Pi))*sin(n*x)*exp(-n^2*t)/Pi^2, n = 1 .. infinity))*Pi-Pi*(exp(-9*t)-exp(-t))*sin(3*x)+8*x)/Pi


pdetest(%, [pde__6, iv__6])

[0, 0, 0, (-phi(x)*Pi^2+Pi*x+2*(Sum((Int(-(-phi(x)*Pi+x)*sin(n*x), x = 0 .. Pi))*sin(n*x), n = 1 .. infinity)))/Pi^2]



More accuracy when returning series solutions that have exceptions for certain values of the summation index or a parameter



Example 1: the answer to this problem was previously given with n = 0 .. infinity instead of n = 1 .. infinity as it should be:

pde__7 := diff(v(x, t), t, t)-(diff(v(x, t), x, x))

iv__7 := v(0, t) = 0, v(x, 0) = -(exp(2)*x-exp(x+1)-x+exp(1-x))/(exp(2)-1), (D[2](v))(x, 0) = 1+(exp(2)*x-exp(x+1)-x+exp(1-x))/(exp(2)-1), v(1, t) = 0

pdsolve([pde__7, iv__7])

v(x, t) = Sum(-2*sin(n*Pi*x)*((Pi^2*(-1)^n*n^2-Pi^2*n^2+2*(-1)^n-1)*sin(Pi*t*n)-(-1)^n*cos(Pi*t*n)*Pi*n)/(Pi^2*n^2*(Pi^2*n^2+1)), n = 1 .. infinity)



Example 2: the answer to exercise 6.25 from Pinchover and Rubinstein is now given in a much simpler format, with the special limit case for w = 0 calculated separately:

pde__8 := diff(u(x, t), t) = k*(diff(u(x, t), x, x))+cos(w*t)
iv__8 := (D[1](u))(L, t) = 0, (D[1](u))(0, t) = 0, u(x, 0) = x

`assuming`([pdsolve([pde__8, iv__8], u(x, t))], [L > 0])

u(x, t) = piecewise(w = 0, (1/2)*L+Sum(2*L*(-1+(-1)^n)*cos(n*Pi*x/L)*exp(-Pi^2*n^2*k*t/L^2)/(n^2*Pi^2), n = 1 .. infinity)+t, (1/2)*(L*w+2*(Sum(2*L*(-1+(-1)^n)*cos(n*Pi*x/L)*exp(-Pi^2*n^2*k*t/L^2)/(n^2*Pi^2), n = 1 .. infinity))*w+2*sin(w*t))/w)



Improved handling of piecewise, eval/diff in the given problem



Example 1: this problem, which contains a piecewise function in the initial condition, can now be solved:

pde__9 := diff(f(x, t), t) = diff(f(x, t), x, x)
iv__9 := f(0, t) = 0, f(1, t) = 1, f(x, 0) = piecewise(x = 0, 0, 1)

pdsolve([pde__9, iv__9])

f(x, t) = Sum(2*sin(n*Pi*x)*exp(-Pi^2*n^2*t)/(n*Pi), n = 1 .. infinity)+x



Example 2: this problem, which contains a derivative written using eval/diff, can now be solved:

pde__10 := -(diff(u(x, t), t, t))-(diff(u(x, t), x, x))+u(x, t) = 2*exp(-t)*(x-(1/2)*x^2+(1/2)*t-1)

iv__10 := u(x, 0) = x^2-2*x, u(x, 1) = u(x, 1/2)+((1/2)*x^2-x)*exp(-1)-((3/4)*x^2-(3/2)*x)*exp(-1/2), u(0, t) = 0, eval(diff(u(x, t), x), {x = 1}) = 0

pdsolve([pde__10, iv__10], u(x, t))

u(x, t) = -(1/2)*exp(-t)*x*(x-2)*(t-2)





Pinchover, Y. and Rubinstein, J.. An Introduction to Partial Differential Equations. Cambridge UP, 2005.



Katherina von Bülow

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

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

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..]); 

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.


Mukhametshina Liya

Games with pseudo-fractals




Aleksandrov Denis,
7th grade
secondary school #57 of Kazan


vv if you could please help adjust your code.  I've adjusted the start of the eurocup code to match the world cup however I haven't decoded your coding and probably won't be able to have time before the world cup starts.  I've got as far as adding the teams, flags and ratings of each team.

Let me just say while copying and pasting the flag bytes to the code, Maple became a bitch to work worth (pardon my language) but I became so frustated because my laptop locked up twice.  The more I worked with Maple the slower it got, until it froze right up.  Copying and pasting large data in maple is almost to near IMPOSSIBLE.  .. perhaps this could be a side conversation.

Here's the world cup file so far.

**edit added**
Fixed flag sizes, couple of other fixes in other stats and added some additional stats


ANIMATED image of cascade of opening matryoshkas

E.R. Ibragimova




1 2 3 4 5 6 7 Last Page 1 of 51