Since we are dealing with time series data for the visualization at the University of Louisville, one of the features I’ve wanted to add to the chart was smooth transitioning from one time series graph to the next. I was so busy building other graphs though that I never had time to figure out the necessary tweening to get the charts to move smoothly. But recently I took the time to figure this out and thought I would follow up the last post with a discussion on this!

Here is a link to the example source code as well, feel free to take it and learn from it, and hopefully this helps you figure out how to better do your own tweening for charts that you might not be able to find examples for anywhere else online.

Polar Area Diagram Transitioning Source Code

We start out with the same code that we finished up with to build the Polar Area Diagram. I won’t discuss this code again and would defer you to the other blog entry for this. We’re going to add the below function – and I will discuss it further after.

function transition( val ) { var bar = d3.svg.arc() .innerRadius( 0 ) .outerRadius( function(d,i) { return radius( timeseries[val][0][i] ); }); d = []; for(i = 0; i<timeseries[val][0].length; i++) { d.push(1); } newRadius = []; for(i in timeseries[val][0]) { newRadius.push( radius( timeseries[val][0][i] )); } path = d3.selectAll("#radial svg g.series path"); path.each(function(dat,s) { d3.select(this) .transition() .duration(800) .attrTween("d", function(a) { var k = d3.interpolate(oldRadius[s], newRadius[s]); return function(t) { return bar.outerRadius(k(t))(a); }; }).each("end", function() { oldRadius[s] = newRadius[s]; }); }); } |

In this function the first few lines are just setting the function up. Since I declared bar in another function in the JavaScript, I am just copying that into this function as well. The next line builds out the ones array ( e.g. [1,1,1,1,1] ) as I had done previously. These could be ripped out and made globally if one wanted, but I didn’t when I rewrote this function.

The next line builds out the Radii for the location that we are transitioning to. For this, we just pass in the data to the radius function that we declared previously to build out the array necessary for the transitions. In the previous function “drawBars” where we declare bar, we also need to build out an array for the oldRadius. This is fairly simple as we just change the declaration of bar there to read:

var bar = d3.svg.arc() .innerRadius( 0 ) .outerRadius( function(d,i) { oldRadius[i] = radius( timeseries[val][0][i] ); return radius( timeseries[val][0][i] ); }); |

Notice that we are doing something similar to building the newRadius variable, but instead we are doing this inside of the outerRadius function on the declaration of bar.

Back to the original code, the next lines are the important bits as this is where the transitioning actually occurs. First we need to grab all of the path elements that we will be transitioning. We cannot just grab the paths, but d3 selections use CSS selectors, so we can explicitly grab the paths that we want using the “#radial svg g.series path” selector to grab all of the arc paths.

The next line loops through each of the selected paths and runs the function passing in the object (dat) and the array key of the object (s). Despite having the actual object, we need to do another select on the object, so we can use d3.select(this). We tell the selection that we are transitioning with a specified duration (800 ms in this example). The next portion is the attrTween.

Since we are changing the heights of the outerRadius, we need to run an attrTween on the “d” attribute (the SVG data attribute). And here is where things start to get more interesting. We then use a d3 interpolation to build the transition from one object to the next. This line:

var k = d3.interpolate(oldRadius[s], newRadius[s]); |

takes the oldRadius value – remember we set that in the declaration of “var bar” in the drawBars function – and the newRadius value that we just declared in this section and builds all of the values that are needed in between. This builds a function that we can use to pass in the time value. We finish this tween by returning a function that takes in the parameter of time (t) and changes the outerRadius at every given t. Since we are not changing the size of the width of the bars (the remain constant, we can pass in the value that they were previously in the second ()() of the outerRadius function. Notice that in the attrTween function we pass in the parameter “a”, which is actually the width of the given bar, so we can just use this value to keep it constant.

This gives us a smooth transition from one time series point to another, but if we want to continue to allow the transitions to occur smoothly we have to switch the oldRadius with the newRadius after the transition is completed. While I had originally attempted to call this directory after the loop of each path, this caused an issue with the transitions. The transition does not have to complete to run the code afterward. Instead, to complete this, we have to include a .each() after the .attrTween(). We can use the “end” keyword to listen for the end of the tweening and we then give this a callback function. Here I take the newRadius[s] value and switch the oldRadius[s] value.

Assuming everything was done correctly, You should now have smooth transitions between graphs, that look something like this:

]]>

You can find all of the source code for the tutorial in working HTML/JS files in the below link:

Polar Area Diagram Source Code

D3 provides a rich javascript library for data visualization. Unfortunately, as I began to do more research, I noticed that no one had created a Polar Area Diagram. Of course, this being a requirement, I have had to sit down and create a way of creating this chart. Fortunately, it wasn’t nearly as difficult as I had initially thought, it was just a culmination of various pie charts combined with different outer radii, but I thought I would write something up to help someone else get started on something similar if it is needed.

Here’s the data creation for the charts discussed here:

var randomFromTo = function randomFromTo(from, to){ return Math.random() * (to - from) + from; }; timeseries = []; sdat = []; keys = ["x", "y", "z", "w", "u", "t"]; for (j = 0; j < time; j++) { series = [[]]; for (i = 0; i < axis; i++) { series[0][i] = randomFromTo(minVal,maxVal); } for (i=0; i<=numticks; i++) { sdat[i] = (maxVal/numticks) * i; } timeseries[j] = series; } |

I’m going to assume that if you are reading this, you at least have a little bit of knowledge of the D3 libarary. As with all charts in D3, we start by creating an SVG tag (or there are ways of using the canvas object as well).

var w = 400; var h = 400; viz = d3.select("#radial") .append('svg:svg') .attr('width', w) .attr('height', h); viz.append("svg:rect") .attr('x', 0) .attr('y', 0) .attr('height', 0) .attr('width', 0) .attr('height', 0); vizBody = viz.append("svg:g") .attr('id', 'body'); |

From here we’ll have to do a little bit of mathematics to create the radial (circular) axis ticks. First we’ll create a padding for the image, and we’ll also, in this example, fix the maximum value to 6. We’ll also transform the image so that our centroid of the chart is located in the middle instead of the top-left corner of the image.

var vizPadding = { top: 25, right: 25, bottom: 25, left: 25 }; var maxVal = 6; //need a circle so find constraining dimension heightCircleConstraint = h - vizPadding.top - vizPadding.bottom; widthCircleConstraint = w - vizPadding.left - vizPadding.right; circleConstraint = d3.min([heightCircleConstraint, widthCircleConstraint]); // create a function for calculating the radius of a point from the center radius = d3.scale.linear().domain([0, maxVal]) .range([0, (circleConstraint / 2)]); radiusLength = radius(maxVal); //attach everything to the group that is centered around middle centerXPos = widthCircleConstraint / 2 + vizPadding.left; centerYPos = heightCircleConstraint / 2 + vizPadding.top; vizBody.attr("transform", "translate(" + centerXPos + ", " + centerYPos + ")"); |

Now we can start adding our bars to the charts, or if we want the axes to exist behind the bars, we could add those next. Up to now, I have assumed you have some knowledge of the d3.scale and creation of the svg object. I stay with some of those assumptions, but I’ll explain the bars in a little more depth here. First, the code:

pie = d3.layout.pie().value(function(d) { return d; }).sort(null); d = []; for(i = 0; i < timeseries[val][0].length; i++) { d.push(1); } groups = vizBody.selectAll('.series') .data([d]); groups.enter().append("svg:g") .attr('class', 'series') .style('fill', "blue") .style('stroke', "black"); groups.exit().remove(); bar = d3.svg.arc() .innerRadius( 0 ) .outerRadius( function(d,i) { return radius( timeseries[val][0][i] ); }); arcs = groups.selectAll(".series g.arc") .data(pie) .enter() .append("g") .attr("class", "attr"); arcs.append("path") .attr("fill", "blue") .attr("d", bar) .style("opacity", 0.4); |

Now here is where we use a pie chart in a slightly different way. You’ll notice we created our pie object near the top of this code. Of course, since we have six axes, each one will likely have a different height. The *d* variable does exactly this. We’ll use this variable – which is just an array length of 6 where each element contains the value 1. What this does is ensure that the angle of the “bars” that we are creating are equal.

The next bit of code for the *group* variable simply loads the data and creates a <g> tag in the svg that we can place our paths. Just like a d3 pie chart, we’re going to create an arc(). However, we are going to change the outer radius of the pie wedge to match with the radius of our data’s value. Since we created the radius() previously, we can use this function to calculate the outer radius of this wedge. Instead of using the d value that gets passed into the function that is calculating the radius, we’re going to pass this function the timeseries variable data for that wedge – *i*.

From there everything is the same as a standard pie chart. Simply pass the bar object to the path’s *d* attribute as shown and we get bars.

We can also add axes, text, and circular ticks if we’d like, as shown below:

var radialTicks = radius.ticks(numticks), lineAxes; vizBody.selectAll('.line-ticks').remove(); lineAxes = vizBody.selectAll('.line-ticks') .data(keys) .enter().append('svg:g') .attr("transform", function (d, i) { return "rotate(" + ((i / axis * 360) - 90) + ")translate(" + radius(maxVal) + ")"; }) .attr("class", "line-ticks"); lineAxes.append('svg:line') .attr("x2", -1 * radius(maxVal)) .style("stroke", ruleColor) .style("fill", "none"); lineAxes.append('svg:text') .text(function(d,i){ return keys[i]; }) .attr("text-anchor", "middle"); vizBody.selectAll('.circle-ticks').remove(); circleAxes = vizBody.selectAll('.circle-ticks') .data(sdat) .enter().append('svg:g') .attr("class", "circle-ticks"); circleAxes.append("svg:circle") .attr("r", function (d, i) { return radius(d); }) .attr("class", "circle") .style("stroke", ruleColor) .style("fill", "none"); circleAxes.append("svg:text") .attr("text-anchor", "left") .attr("dy", function (d) { return -1 * radius(d); }) .text(String); |

When everything is created, we should get a radial bar graph that looks like the chart below! Then you can just play around with the styling a bit more. You can add better looking headers for the text, align the axis text to be centered over the bar (with a little bit of trigonometry), and even build the bars backwards (inner radius is the “timeseries” value, and outer radius is the maximum Value) so that a gradient can be added to the “bars”. But hopefully this gets someone started on a graph like this.

Use these graphs sparingly! They don’t always show what you might want them to show, and comparing differences between bars is difficult in circular form. In most cases, I would recommend using bar charts. For more information on when to use various graphs, Stephen Few’s work in information visualization would be a good place to start.

]]>Let us consider a nonlinear optimization problem:

Minimize

subject to:

We will let represent a relative minimum point for our problem, which also satisfies some constraint qualification. With this, then we can assume that for every element there exists a vector , where *l* represents the number of equality constraints, and , where *m* represents the number of inequality constraints. These constants, and , are called KKT multipliers.

In order for the KKT conditions to be held in a nonlinear programming problem (NLP), then each of three conditions must be met [1-4]. The Primal Feasibility restates what the problem states, that the inequality and equality constraints on must be met in order for the problem to be optimal:

The second condition is known as the dual feasibility condition. In this condition states, rather verbosely, that every element in must be greater than zero, and that the stationarity of the problem must be equal to 0.

The stationarity of the problem is:

While the other two are simply conditions that *λ* and *μ* must meet in order for to be optimal.

The third condition that must be met is known as complementary slackness. This condition simply states that for each mu and its respective inequality constraint, the product of the two should result in zero:

When these three conditions are met, we have met the KKT conditions and our solution, , is an optimal solution for the NLP problem. There maybe more than one *x* in the space which meet the conditions. Any point in the problem space where every element of *λ* and *μ*, such that the tuple (x, *λ*, *μ*) satisfy the KKT conditions are called KKT points. Derivation of these constraints can be found in [1,2]

As mentioned previously, the points that we are testing need to meet some qualification in order for the point to be considered. The most well known constraint Qualification is the Linear Independence constraint Qualification (LICQ), which simply states that and are linearly independent from the other at point . The Mangasarian-Fromovitz constraint qualification (MFCQ) states similarly the LICQ with the addition of being positive-lineraly independent at . [5]

There are however other constraint qualifiers that relax the LICQ. The Slater constraint qualifier can be used in convex problems. If there exists a point x such that and for all i,j active in , then the slate condition holds. [5,6]

Other types of constraint qualifiers do exist, but these three seem to be the most commonly used in KKT qualification.

[1] Kuhn, H. and Tucker, A., "Nonlinear Programming" *Proceedings of the 2nd Berkeley Symposium* 1951, pp. 481-492.

[2] Karush, W., “Minima of Functions of Several Variables with Inequalities as Side Constraints”. M.Sc. Dissertation, Univ. of Chicago, Chicago, Il, 1939.

[3] Kuhn, M. “The Karush-Kuhn-Tucker Theorem”, Internet: http://smp.if.uj.edu.pl/~kopiec/MT/Materialy/KarushKuhnTucker.pdf, *CDSEM Uni. Mannheim*, 2006.

[4]McCarl, B. and Spreen, T., “Nonlinear Optimization Conditions”, Ch. 12, Applied Mathematical Programming Using Algebraic Systems. Internet: http://agecon2.tamu.edu/people/faculty/mccarl-bruce/mccspr/thebook.pdf

[5]Eustaquio, R. Karas, E. and Ribeiro, A. Constraint Qualification for Nonlinear Programming, Tech Report, Univ. of Parana.

[6] Tiba, D. and Zalinescu, C. “On the Necessity of some Constraint Qualification Conditions in Convex Programming”, Journal of Convex Analysis, 11 (1), 2004. pp 95-110.

Dido (or Elissa, depending on the reference) is the legendary founder and first Queen of Carthage. Her accounts are mentioned by the historian Justin and later as a part of Virgil’s “Aeneid” poem. In this story, Elissa is said to have escaped Tyre with groups of her brother Pygmalion’s attendants and senators. Eventually Elissa’s party arrived on the coast of Northern Africa where Elissa had asked the local inhabitants for a small area of land for a refuge. The isoparametric problem came into existence. Elissa asked for only as much land as could be encompassed by an oxhide. She used a stroke of mathematical genius, cutting the hide into long, thin strips in order to encircle the entirety of the nearby hill. This land became what is Carthage, and Elissa (or Dido) became the Queen of the city.

The history of Elissa is mentioned by Justin, however, the problem is formulated from a passage in Virgil’s “Aeneid”:

The Kingdom you see is Carthage, the Tyrians, the town of Agenor;

But the country around is Libya, no folk to meet in war.

Dido, who left the city of Tyre to escape her brother,

Rules here – a long and labyrinthine tale of wrong

Is hers, but I will touch on its salient points in order…

Dido, in great disquiet, organized her friends for escape.

They met together, all those who harshly hated the tyrant

Or keenly feared him: they seized some ships which chanced to be ready…

They came to this spot, where today you can behold the mighty

Battlements and rising citadel of New Carthage,

And purchased a site, which was named “Bull’s Hide” after the bargain

By which they should get as much land as they could enclose with a bull’s hide. [1]

Knowing the history helps us to see how this might be useful, but it is not formalized in any mathematical sense. If we think of the problem, the problem becomes similar to what is known in mathematics as the isoperimetric problem. In Dido’s problem, Dido cuts the pieces of the ox-hide into strips, effectively using the area of the hide as the perimeter. From this point, the goal of the Dido problem then is to find the closed curve that has maximal area for a given perimeter. The problem is at this point, the isoperimetric problem.

Isoperimetric, literally means “having the same perimeter”, therefore, we know that the perimeters are fixed and our goals is to simply maximize the area. The isoperimetric problem requires the use of the isoperimetric inequality (and quotient) where if we think planar geometry, we can define a figure to have an area *A* and a perimeter *p*. The quotient then is [2]:

This quotient is derived from the ratio of the curve area to the area of a circle () with the same perimeter as the curve (). We can therefore derive the quotient:

Mathematics tells us that this inequality holds for the shape of a circle only. Mathematical Proofs for this concept representing a can be found at [3-6]

In combinatorics and computer science, the use of Isoperimetric inequalities (the basis of the Dido problem) plays a role in designing robust computer networks, several applications in complexity theory, and error-correcting codes, through the use of expander graphs.[7] Expander graphs are a sparse graph with strong connectivity properties. The isoperimetric problems in graph theory (described on page 470 of [7]) then have usefulness in graph optimization problems for expander graphs.

There are perhaps many other applications of the Isoperimetric problem and the Dido problem, as the Dido problem is in itself an optimization of maximal area given a perimeter.

[1] Virgil. Trans. by C.D. Lewis. Book 1, lines 307-372 in *The Aeneid*. New York: Doubleday, pp 22-23. 1953.

[2] Osserman, R. “Isoperimetric Inequalities.” Appendix 3, Sec 3 in *A Survey of Minimal Surfaces.* New York: Dover, pp. 147-148, 1986.

[3] Bonnesen, *Les Problèmes des Isopérîmètres et des Isépîphanes*. Paris: Gauthier-Villars, pp 59-61, 1929.

[4] Bonnesen, T. and Fenchel, W., *Theorie der Convexen Körper*. Chelsea Publishing, New York, S.111-112, 1948.

[5] Magnani, C. “The Problem of Dido” Internet: http://mathematicalgarden.wordpress.com/2008/12/21/the-problem-of-dido/, December 2008 [September 5, 2011].

[6] Luthy, P. “Two Cute Proofs of the Isoperimetric Inequality” Internet: http://cornellmath.wordpress.com/2008/05/16/two-cute-proofs-of-the-isoperimetric-inequality/, May 16, 2008 [September 5, 2011].

[7]Hoory, S., Linial, N., and Wigderson, A. “Expander Graphs and Their Applications” *Bulletin of the American Mathematical Society* 43 (4): 439-561, 2006. dpi: 10.1090/S0273-0979-06-01126-8.

We can construct a Lagrangian function as shown below. [1] We assume that function, *f*, is the problem for which an extremum of a function is desired:

with a set of any number of constraint functions:

Then our Lagrangian function is defined as:

The Lagrangian multiplier can be used in any multidimensional space. The example below is given in [2].

A box is to be constructed out of various materials. The material to be used for the front and back sides costs $1 per square meter. The material to be used for the left and right sides costs $2 per square meter. The material to be used for the top and bottom costs $4 per square meter. What is the maximum volume that can be enclosed for a total material cost of $192?

We know the constraint, C. We should also know that the Volume of a cube (box) is . We must find the constraint function…

Since we have a front and back side that cost $1 each, we have 2 planes that are length times width. We have a left and right side that cost $2 each at width time height. And lastly, we have a top and bottom side that cost $4 each at length times width:

We can then write our Lagrangian function:

If we continue solving this out using partial derivatives and some algebraic techniques, as shown in [2], we eventually determine the maximal volume for the cost, C, of $192, is a Volume of 64 meters^{3}. This is an example of how we can use the Lagrangian multiplier in a 3-dimensional space. The multiplier can work in any higher dimensional space as well.

What does the Lagrangian multiplier, λ, represent then? Well in the problems above, the Lagrangian multiplier represents a scalar value that allows us to change the size of the values used to scale the shape (circle in the contour map, and cube in the Volume problem). However, the Lagrangian multiplier can be used to represent actual values as well. [3] shares some examples of what the λ functions can represent in both physics and economics.

In the case of the physics of forces and potential energy, we might think of the constraint functions as representing forces that are helping to bring a point to it minimum or maximum. The Multiplier can then be thought of as a measure of how hard the constraint has to pull in order to balance our the forces on the constraint surface. In economics, we might think of maximizing profits based on some limited number of resources. The multiplier then represents the marginal value of the resource, or the rate at which the function changes if we change the constraints.

Therefore, understanding what the multiplier means takes an understanding of the problem that it is being applied. In some cases, it may only be a scaling value; in others, it may have a more significant meaning.

The Lagrangian Multiplier is useful in the field of optimal control theory. The multipliers can be interpreted as a cost ate variables. In Pontryagin’s maximum principle (or minimum principle), applied to deterministic problems, yields the same solution as many of the Bellman principles of Dynamic Programming, without the curse of dimensionality. The multiplier then works as a means of deriving the optimal minimum or maximum in control theory in a quicker means than Bellman’s equations for dynamic programming in higher dimensional spaces. [4]

[1] Vapnyarkii, I.B., “Lagrange multipliers” in *Encyclopaedia of Mathematics*, New York: Springer, 2001.

[2] Hahn, K. *Lagrange Multiplier Method for finding Optimums* Internet: http://www.karlscalculus.org/pdf/lagrange.pdf [September 5, 2011]

[3] Jensen, S. *An Introduction to Lagrange Multipliers* Internet: http://www.slimy.com/~steuard/teaching/tutorials/Lagrange.html [September 5, 2011]

[4] Todorov, E. “Optimal Control Theory” in Bayesian Brain, Boston: MIT Press, 2006.

The Euclidean Algorithm is relatively simple to program. Below is an implementation of the Euclidean Algorithm in Java.

public int Euclid(int m, int k) { if(k==0) return m; else return this.Euclid(k, m%k); } |

The Bjorklund algorithm uses a similar concept to the Euclidean algorithm, but is used to distribute the zeros in a binary set evenly. The simplest, visual way of thinking about the Bjorklund can be described as thinking of a binary set as columns. The example below shows a Euclidean set of (4, 6) which we can describe as four 1s and six 0s. We therefore can create the initial binary set of “1111000000”. From here we choose the smallest of the two numbers and move that number of zeros at the end of the set to the first 1 to n columns. We update the numbers using the Euclidean Algorithm and continue this step until we are left with 0 or 1 column left, then we concatenate the remaining columns into a new set. A visual example of the (4,6) version of the Bjorklund algorithm is found below.

1111000000 111100 0000 1111 0000 00 11 00 00 11 00 1001010010

This algorithm was originally used with the operation of the components on the spallation neutron source (SNS) accelerators in nuclear physics. However, if we say that every one is associated with an accented note and the zeroes are unaccented, or rests, we can use this to generate the general rhythms and various world music rhythms. For this reason, the Bjorklund algorithm is a unique and powerful algorithm in any music generator. Below is an example Bjorklund algorithm implemented in Java (Special Thanks to Douglas Ferguson for catching some issues in the code and helping to resolve those issues):

import java.util.*; public class Bjorklund { private ArrayList<Boolean> rhythm = new ArrayList<Boolean>(); int pauses, per_pulse, remainder, steps, pulses, noskip, skipXTime; boolean switcher; public Bjorklund(int pulses, int steps) { this.steps = steps; this.pulses = pulses; this.pauses = steps - pulses; this.switcher = false; if (this.pulses > this.pauses) { this.switcher = true; // XOR swap pauses and pulses this.pauses ^= this.pulses; this.pulses ^= this.pauses; this.pauses ^= this.pulses; } this.per_pulse = (int) Math.floor(this.pauses / this.pulses); this.remainder = this.pauses % this.pulses; this.noskip = (this.remainder == 0) ? 0 : (int) Math.floor(this.pulses / this.remainder); this.skipXTime = (this.noskip == 0) ? 0 : (int)Math.floor((this.pulses - this.remainder)/this.noskip); this.buildRhythm(); if(this.switcher) { // XOR swap pauses and pulses this.pauses ^= this.pulses; this.pulses ^= this.pauses; this.pauses ^= this.pulses; } } public Bjorklund(int pulses, int steps, String expected) { this(pulses, steps); autorotate(expected); } private void buildRhythm() { int count = 0; int skipper = 0; for (int i = 1; i <= this.steps; i++) { if (count == 0) { this.rhythm.add(!this.switcher); count = this.per_pulse; if (this.remainder > 0 && skipper == 0) { count++; this.remainder--; skipper = (this.skipXTime > 0) ? this.noskip : 0; this.skipXTime--; } else { skipper--; } } else { this.rhythm.add(this.switcher); count--; } } } public ArrayList<Boolean> getRhythm() { return this.rhythm; } public int getRhythmSize() { return this.rhythm.size(); } public void autorotate(String expected) { boolean verified = false; int size = this.rhythm.size(); int rotate = 1; this.rotateRightByPulses(0); String found = this.getRhythmString(); while(!found.equals(expected) || rotate < this.pulses) { this.rotateRightByPulses(1); found = this.getRhythmString(); if(found.equals(expected)){ verified = true; break; } } if(!verified) { System.err.println("Rhythmic string passed cannot be generated from E("+this.pulses+","+this.steps+")"); } } public void rotateRightByBits(int numBits) { Collections.rotate(this.rhythm, numBits); } public void rotateRightByPulses(int numPulses) { for (int i = 0; i < numPulses; i++) { int rotater = this.rhythm.size() - 1; int count = 1; while (this.rhythm.get(rotater) == false) { rotater--; count++; } this.rotateRightByBits(count); } } private String getRhythmString(){ Iterator<Boolean> iterator = this.rhythm.iterator(); StringBuffer buffer = new StringBuffer(); while(iterator.hasNext()){ buffer.append(iterator.next() ? "x" : "."); if(iterator.hasNext()){ buffer.append(" "); } } return buffer.toString(); } private void print() { System.out.println(this.pulses + ":" + this.steps +" -> "); System.out.print(this.getRhythmString()); System.out.println(); } public void autoverify(String expected) { boolean verified = false; int size = this.rhythm.size(); int rotate = 1; this.rotateRightByBits(0); String found = this.getRhythmString(); while(!found.equals(expected) || rotate < size) { this.rotateRightByBits(1); found = this.getRhythmString(); if(found.equals(expected)){ System.out.println("E("+this.pulses+","+this.steps+") verified for <<" + found + ">> by rotating bits right "+rotate+" times"); verified = true; break; } rotate++; } if(verified == false) { System.err.println("missed E("+this.pulses+","+this.steps+") expected: <<"+ expected + ">> but found: <<"+found+">>"); } } } |

An example of how to call this class:

import java.util.*; public class test { public static void main(String[] args) { Bjorklund b = new Bjorklund(5,9); b.rotateRightByPulses(1); ArrayList r = b.getRhythm(); System.out.println(Arrays.toString(r.toArray())); } } |