text:
## Monday, July 4, 2016

### Monte Carlo Integration in Scala

This post introduces an overlooked numerical integration method leveraging the ubiquituous Monte Carlo simulation.
Not every function has a closed form for computing a definite integral known as symbolic integration. There are many numerical integration method for continuous functions such as Simpson's formula, Newton-Cotes quadrature rule and Gaussian quadrature. These methods are deterministic by nature.
The Monte-Carlo numerical integration is a stochastic method that relies on randomly generated values to estimate the area under a curve, surface or any multidimensional space. The illustration of the Monte Carlo integration method uses a pragmatic uniform random distribution of data points for single variable function.

Basic concept
Let's consider the single variable function illustrated in the following line plot.
$f(x)=\frac{1}{x}-0.5$

The objective is to compute the integral of the function over the interval [1, 3]. The Monte Carlo numerical integration is defined by three steps:
• Define the outer area of the function defined by the minimum and maximum values of x and y, in this case x [1, 3] and y [0.5, -0.12]
• Generate random data points between over the outer area
• Compute the ratio of the number of random data points within the function area over the total number of data points
Let's define a generic class, MonteCarloIntegrator to encapsulate these 3 steps:
The class has two arguments (line 1)
• The function f to sum
• The number of random data points used in the methodology

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class MonteCarloIntegrator(f: Double => Double, numPoints: Int) { def integrate(from: Double, to: Double): Double = { val (min, max) = getBounds(from, to) val width = to - from val height = if (min >= 0.0) max else max - min val outerArea = width * height val randomx = new Random(System.currentTimeMillis) val randomy = new Random(System.currentTimeMillis + 42L) def randomSquare(randomx: Random, randomy: Random): Double = { val numInsideArea = Range(0, numPoints)./:(0)( (s, n) => { val ptx = randomx.nextDouble * width + from val pty = randomy.nextDouble * height randomx.setSeed(randomy.nextLong) randomy.setSeed(randomx.nextLong) s + (if (pty > 0.0 && pty < f(ptx)) 1 else if (pty < 0.0 && pty > f(ptx)) -1 else 0) } ) numInsideArea.toDouble * outerArea / numPoints } randomSquare(randomx, randomy) } }

The method integrate implements the sum of the function over the interval [from, to] (line 3). The first step is to extract the bounds getBounds of the outer area (line 4) which size is computed on line 7. Each coordinate is assigned a random generator randomx and randomy (lines 8 & 9).
The nested method randomSquare records the number of data points, numInsideArea that falls into the area delimited by the function (line 13 - 21). The sum is computed as the relative number of data points inside the area delimited by the function (line 24).

The method getBounds is described in the following code snippet. It is a simple, although not particularly efficient approach to extract the boundary of the integration. It breaks down the interval into of steps (lines 2 & 3) and collects the minimum and maximum values of the function (lines 7 - 12).

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def getBounds(from: Double, to: Double): (Double, Double) = { val numSteps = Math.sqrt(numPoints).floor.toInt val stepSize = (to - from) / numSteps (0 to numSteps)./:((Double.MaxValue, -Double.MaxValue))( (minMax, n) => { val y = f(n * stepSize + from) updateBounds(y, minMax) match { case 0x01 => (y, minMax._2) case 0x02 => (minMax._1, y) case 0x03 => (y, y) case _ => minMax } } ) } def updateBounds(y: Double, minMax: (Double,Double)): Int = { var flag = 0x00 if (y < minMax._1) flag += 0x01 if (y > minMax._2) flag += 0x02 flag }

Precision, precision
You may wonder about the accuracy of the Monte Carlo method and how many randomly generated data points are needed for a decent accuracy. Let's consider the same function $f(x)=\frac{1}{x}-0.5$ and its indefinite integral, that is used to generated the expected sum for the function f $\int f(x)dx=log(x)-\frac{1}{2x}+C$ The simple test consists of computing the error between the value produced by the definite integral and the sum from the Monte Carlo method as implemented in the following code snippet.

 1 2 3 4 5 6 7 8 val fct =(x: Double) => 2 * x - 1.0 val integral = (x: Double, c: Double) => x*x - x + c) final val numPoints=10000 val integrator = new MonteCarloIntegrator(fct, numPoints) val predicted = monteCarloIntegrator.integrate(1.0, 2.0) val expected = integral(2.0, 0.0) - integral(1.0, 0.0)

We run the test 100 times for number of random data points varying between 100 and 50,000.

Monte Carlo is reasonably accurate even with a small number of data points. In this case, the small increase in accuracy does not justify the need to randomize a significant number of data points beyond 1000 data points.

A smarter approach would be to rely on a exit condition to complete the summation in the shortest time possible without having to estimate the optimum number of random data points. A new batch of numPoints rand data points is added at each iteration. One simple convergence criteria compares the difference of the sum between two consecutive iterations:
  sum(existing data points + new batch data points) - sum(existing data points) < eps

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 def randomSquare(randomx: Random, randomy: Random): Double = { var oldValue = 0.0 Range(0, numPoints).takeWhile(_ => { val numInsideArea = .... // ... s + .... }) val newValue = numInsideArea.toDouble * outerArea / numPoints val diff = Math.abs(newValue - oldValue) oldValue = newValue diff < eps }) oldValue }

At each iteration, a new batch of numPoints data points is randomly generated to enhance the accuracy of the summation. The exit strategy is implemented through the higher order Scala collection method takeWhile (lines 3 & 11).

Note: This implementation of the Monte Carlo integration is simple enough to illustrate the concept of stochastic methods applied to calculus. The recursive stratified sampling has been shown to be more accurate for computing definite integral of function with significant inflection points (extreme second order derivative).

References
Monte Carlo Integration Dartmouth College - C. Robert, G. Casella
The Clever Machine: Monte Carlo ApproximationsDustin Stansbury
Programming in Scala - 3rd edition M. Odersky, L. Spoon, B. Venners

## Sunday, June 5, 2016

The stochastic gradient descent (SGD) is a critical element in the training of machine learning models such as support vector machines, logistic regression or back-propagation neural networks. In its simplest incarnation, the gradient is computed using a single learning rate.
However, it is not uncommon for the features of a model to have a wide range of variance between observations. In this case an adaptive gradient algorithm, which assign a learning rate for each feature, may be the solution. There are many different approaches to implement per-feature learning rate: this post describes the AdaGrad algorithm and its implementation in Apache Spark 2.0

The stochastic gradient descent is a randomized approximation of the gradient descent (batch) algorithm to minimize a continuous differentiable objective function. In supervised machine learning, the objective function is a loss function (logistic, sum of squares..).
$L(w)=\frac{1}{n}\sum_{i=0}^{n}(y_{i}-f(x_{i}|w))^{2}$ The objective function L is expressed as the summation of differentiable functions. In the case of the loss function in supervised learning, the differentiable functions are the loss related to a specific feature. $L(w)=\sum_{i=1}^{n}L_{i}(w)$ In supervised learning, the vector w represent the vector of weights (or model parameters). At each iteration of the stochastic gradient descent, the weights are updated using the formula $w_{t+1}=w_{t}-\eta \sum_{i=0}^{n}\frac{\partial L}{\partial w_{i, t}}$ The stochastic gradient descent (SGD) minimizes the loss function between the expected value and the predictive values generated by the model. At each iteration, SGD, select a subset of the observations (known as a mini-batch) used in the training of the model. The iterative process is expected to converged toward the true global minimum of the loss function.

The main reason behind AdaGrad is the need to increase the learning rate for the sparse features (or model parameters) and decrease the learning rate for features that are denser. Therefore, AdaGrad improves the convergence of the minimization of the loss for model with sparse features, given that these sparse features retains information.
$w_{t+1}=w_{t} -\frac{1}{\sqrt{\sum_{t=1}^{T}\bigtriangledown _{ti}^{t} + \varepsilon }}\frac{\partial L}{\partial w_{ti}}$

SGD in Apache Spark
The Apache spark MLlib library has two implementations of SGD
• Generic Gradient Descent and related classes in the mllib.optimization package
• SGD bundled with classifier or regression algorithms such as LogisticRegressionWithSGD, LassoWithSGD, SVMWithSGD or RidgeRegressionWithSGD
We will be using the optimization package in order to customize the stochastic gradient descent. The objective is to leverage the mllib.optimization.GradientDescent template class and implement the adaptive gradient with per-feature learning rate by creating a customize Updater.
The updater "updates the weights of the model" (Logistic regression or SVM) with the product of the current learning rate with the partial derivative of the loss over this weight (as described in the previous section). Let's call AdaGradUpdater the updater that implement the update of the model weights using the adaptive gradient. The SGD is then instantiated as follow
   val adaSGD = new GradientDescent.
.setStepSize(0.01)
. .....

  Updater.compute(
oldWeights: Vector,
stepSize: Double,
iter: Int,
regCoefs: Double): (Vector, Double)

The method returns the tuple (vector of new weights, loss)

As mentioned earlier, the implementation of AdaGrad consists of overriding the method Updater.compute
The computation of the learning rate requires us to record the past values of the square value of the gradient (previous steps) for this particular weight, in the array gradientHistory (line 3). First we define the method += to update the gradient history (lines 27-36). The first call to the method creates the gradient history (line 31).
The next step consists of converting the existing (old) weights into a Breeze dense vector brzWeights (line 14). The array of the new learning rates is computed as the inverseVelocity coefficient (line 39).
The learning rates are zipped with the old weights (line 15) to update the weights newWeights as a new dense vector(line 21). The linear algebra (matricial computation) on the Spark data node is actually performed by the LINPACK library under the cover through calls to brzAxpy (line 21) and brzNorm (line 22).

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @DeveloperApi final class AdaGradL2Updater(dimension: Int) extends Updater { private[this] var gradientsHistory: Array[Double] = _ override def compute( weightsOld: Vector, gradient: Vector, stepSize: Double, iter: Int, regParam: Double ): (Vector, Double) = { +=(gradient) val brzWeights: BV[Double] = weightsOld.toBreeze.toDenseVector val sumSquareDerivative = inverseVelocity.zip(brzWeights.toArray) val newWeights: BV[Double] = new DenseVector[Double](sumSquareDerivative.view).map { case (coef, weight) => weight * (1.0 -regParam * coef) }) brzAxpy(-1.0, gradient.toBreeze, newWeights) val norm = brzNorm(brzWeights, 2.0) (Vectors.fromBreeze(brzWeights), 0.5 * regParam * norm * norm) } private def +=(gradient: Vector): Unit = { val grad = gradient.toArray grad.view.zipWithIndex.foreach { case (g, index) => { if (gradientsHistory == null) gradientsHistory = Array.fill(grad.length)(0.0) val existingGradient = gradientsHistory(index) gradientsHistory.update(index, existingGradient + g*g) } } } def inverseVelocity = gradientsHistory.map(1.0/Math.sqrt(_)) }

References

## Thursday, May 5, 2016

### Bootstrapping by resampling with replacement

Bootstrapping is a statistical resampling method that consists of randomly sampling a dataset with replacement. This technique enables data scientists to estimate the sampling distribution of a wide variety of probability distributions.

Background
One key objective of bootstrapping is to compute the accuracy of any statistic such as mean, standard deviation, median, mode or error. These statistics, s are known as estimators of an approximate distribution. The most common approximate distribution is known as the empirical distribution function. The special case of the observations are independent and evenly distributed, the empirical or approximate distribution can be estimated through resampling.
The following diagram captures the essence of bootstrapping by resampling.

Each of the B bootstrap samples has the same number of observations or data points as the original dataset from which the samples are created. Once the samples are created, a statistical function s such as mean, mode, median or standard deviation is computed for each sample.
The standard deviation for the B statistics should be similar to the standard deviation of the original dataset.

Implementation in Scala
The purpose of this post is to illustrate some basic properties of bootstrapped sampling
• Profile of the distribution of statistics s for a given probability distribution
• Comparison of the standard deviation of the statistics s with the standard deviation of the original dataset

Let's implement a bootstrap by resampling in Scala, starting with a class Bootstrap.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Bootstrap( numSamples: Int = 1000, s: Vector[Double] => Double, inputDistribution: Vector[Double], randomizer: Random ) { lazy val bootstrappedReplicates: Array[Double] = ( 0 until numSamples )./:( new mutable.ArrayBuffer[Double] )( ( buf, _ ) => buf += createBootstrapSample ).toArray def createBootstrapSample: Double {} lazy val mean = bootstrappedReplicates.reduce( _ + _ )/numSamples def error: Double = {} }

The class Bootstrap is instantiated with a predefine number of samples, numSamples (line 2), a statistic function s (line 3), a dataset generated by a given distribution inputDistribution (line 4) and a randomizer (line 5).
The computation of the bootstrap replicates, bootstrappedReplicates is central to resampling (lines 8 - 11). As described in the introduction, a replicate, s is computed from a sample of the original data set with the method createBootstrapSample (line 10).

Let's implement the method createBootstrapSample.

  1 2 3 4 5 6 7 8 9 10 def createBootstrapSample: Double = s( ( 0 until inputDistribution.size )./:( new mutable.ArrayBuffer[Double] )( ( buf, _ ) => { randomizer.setSeed( randomizer.nextLong ) val randomValueIndex = randomizer.nextInt( inputDistribution.size ) buf += inputDistribution( randomValueIndex ) } ).toVector )

The method createBootstrapSample
- Samples the original dataset using a uniform random function (line 6)
- Applies the statistic function s to this sample dataset (line 1 & 11)

The last step consists of computing the error (deviation) on the bootstrap replicates

 1 2 3 4 5 6 7 8  def error: Double = { val sumOfSquaredDiff = bootstrappedReplicates.reduce( (s1: Double, s2: Double) => (s1 - mean) (s1 - mean) + (s2 - mean)*(s2 - mean) ) Math.sqrt(sumOfSquaredDiff / (numSamples - 1)) }

Evaluation
The first evaluation consists of comparing the distribution of replicates with the original distribution. To this purpose, we generate an input dataset using
• Normal distribution
• LogNormal distribution
Let's create a method, bootstrapEvaluation to compare the distribution of the bootstrap replicates with the dataset from which the bootstrap samples are generated.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 def bootstrapEvaluation( dist: RealDistribution, random: Random, gen: (Double, Double) ): (Double, Double) = { val inputDistribution = (0 until 5000)./:(new ArrayBuffer[(Double, Double)]) ( ( buf, _ ) => { val x = gen._1 * random.nextDouble - gen._2 buf += ( ( x, dist.density( x ) ) ) } ).toVector val mean = (x: Vector[Double]) => x.sum/x.length val bootstrap = new Bootstrap( numReplicates, mean, inputDistribution.map( _._2 ), new Random( System.currentTimeMillis) ) val meanS = bootstrap.bootstrappedReplicates.sum / bootstrap.bootstrappedReplicates.size val sProb = bootstrap.bootstrappedReplicates.map(_ - meanS) // .. plotting histogram of distribution sProb (bootstrap.mean, bootstrap.error) }

We are using the normal and log normal probability density function defined in the Apache Commons Math Java library. These probability density functions are defined in the org.apache.commons.math3.distribution package.
The comparative method bootstrapEvaluation has the following argument:
• dist: A probability density function used to generate the dataset upon which sampling is performed (line 2).
• random: A random number generator (line 3)
• gen: A pair of parameters for the linear transform for the generation of random values (a.r + b) (line 4).
The input distribution inputDistribution { (x, pdf(x)} is generated for 5000 data points (lines 7 - 13).
Next the bootstrap is created with the appropriate number of replicates, numReplicates, the mean of the input dataset as the statistical function s, the input distribution and the generic random number generator of Scala library, as arguments (lines 16 -20).
Let's plot the distribution the input dataset generated from a normal density function.

val (meanNormal, errorNormal) = bootstrap(
new NormalDistribution,
new scala.util.Random,
(5.0, 2.5)
)

Normally distributed dataset
The first graph plots the distribution of the input dataset using the Normal distribution.

The second graph illustrates the distribution (histogram) of the replicates s - mean.

The bootstrap replicates s(x) are also normally distributed. The mean value for the bootstrap replicates is 0.1978 and the error is 0.001691

Dataset with a log normal distribution
We repeat the same process for the lognormal distribution. This time around the dataset to sample from follows a log-normal distribution.

val (meanLogNormal, errorLogNormal) = bootstrap(
new LogNormalDistribution,
new scala.util.Random,
(2.0, 0.0)
)

Although the original dataset used for generated the bootstrap samples is normally distribured, the bootstrap replicates s(x) are normally distributed. The mean for the bootstrap replicates is 0.3801 and the error is 0.002937

The error for the bootstrap resampling from a log normal distribution is twice as much as the error related to the normal distribution
The results is not be a surprise: The bootstrap replicates follow a Normal distribution which matches closely the original dataset created using the same probability density function.

References
Programming in Scala - 3rd edition M Odersky, L. Spoon, B. Venners - Artima - 2016
Elements of Statistics Learning: Data mining, Inference and Prediction - 7.11 Bootstrap method Springer - 2001

## Thursday, April 28, 2016

### Normalized Discounted Cumulative Gain in Scala

This post illustrates the Normalized Discounted Cumulative Gain (NDCG) and it implementation in Scala.
Numerous real-life applications of machine learning require the prediction the most relevant ranking of items to optimize an outcome. For instance

• Evaluate and prioritize counter-measures to cyber-attach
• Ranks symptoms in a clinical trial
• Extract documents relevant to a given topic from a corpus
The Discounted Cumulative Gain (DCG) and its normalized counter part, Normalized Discounted Cumulative Gain (NDCG) is a metric original applied in textual information retrieval and extended to other domains.

Discounted Cumulative Gain
Let's dive into the mathematical formalism for the Discounted Cumulative Gain.

For a indexed target values tj as illustrated in the diagram above, the discounted cumulative gain is computed as
$DCG=\sum_{j=1}^{n}\frac{2^{t_{j}}-1}{log_{2}(j+1)}$ The objective is to compare any given list of ranked/sorted item with a benchmark which represent the optimum ranking (ranking with the highest DCG value).
$p(ranking|IDCG)=\frac{log(2)}{IDCG}\sum_{j=0}^{n}\frac{2^{t_{j}}-1}{log(j+1)}$

Scala implementation
The implementation of the computation of NDCG in Scala is quite simple, indeed. Given a ranked list of items. The three steps are
• Compute the IDCG (or normalization factor)from the list
• Compute the DCG for the list
• Compute the NDCG = DCG/IDCF
First let's consider list of items, of type T to rank. The method ranking to sort a sample of sorted items is provided as an implicit function. The constructor for NDCG has a single argument: the sample of ranking:
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class NDCG[T]( firstSample: Seq[T]) (implicit ranking: T => Int) { import NDCG._ val iDCG: Double = normalize def score: Double = score(initialSample) private def dcg(samples: Seq[T]): Double = samples.zipWithIndex.aggregate(0.0)( (s, samplej) => s + compute(samplej._2 + 1, ranking(samplej._1)) , _ + _) private def normalize: Double = { val sorted = initialSample.zipWithIndex.sortBy{ case (sample, n) => -ranking(sample) }.map( _._1) dcg(sorted) } }

The Ideal Discounted Cumulative Gain, iDCG is compute through the normalize method (line 6). iDCG (normalization factor) is computed by first sorting the items of type T by their value in decreasing order (line 16), then scoring this re-sorted list using the dcg method (line 17).
The computation of the Discounted Cumulative Gain by the method dcg (line 10) is a direct application of the formula described in the previous chapter.
Note: The logarithm function uses a base 2. It is computed as natural log(x)/natural log (2)
Let's now consider a list of items of type Item defined as follows:
case class Item(id: String, x: Double, rank: Int)

The list of items, itemsList is implicitly ranked through the last attribute, rank.

val itemsList = Seq[Item](
Item("1", 3.4, 4), Item("2", 1.4, 3),
Item("3", -0.7, 5), Item("4", 5.2, 2),
Item("5", 1.4, 1))

implicit val ranking = (item: Item) => item.rank

It is time to compute the NDCG coefficient for the list of items, by invoking the score method.

val nDCG = new NDCG[Item](itemsList)

println(s"IDCG = ${nDCG.iDCG}") //45.64 println(s"Score =${nDCG.score}")  // 0.801

The ideal discounted cumulative gain, iDCG is 45.6: It is the optimum ranking for this list of time. The first sample score a probability of 0.8
Note
The DCG of subsequent samples can be computed using the same iDCG value from the same instance of NDCG.

def score(samples: Seq[T]): Double =
if( samples.size != initialSample.size) 0.0
else dcg(samples)/iDCG

References

## Friday, April 15, 2016

### Managing Spark context in ScalaTest

This post describes a methodology to manage the Spark context while testing you application using ScalaTest

Debugging Apache Spark application using ScalaTest seems quite simple when dealing with a single test:
• Specify your Spark context configuration SparkConf
• Create the Spark context
• Clean up resources (Spark context, Akka context, File handles...
However, there are cases when you may need to create and close the spark context used across multiple test or on a subset of the tests. The challenge is to make sure that the Spark context is actually close when it is no longer needed.
This post introduces two basic ScalaTest methods beforeAll and afterAll of the trait BeforeAndAfterAll to manage the context lifecyle of your test application.

Wrapping the Spark context
The objective is to create a small framework that create or retrieve an existing Spark context before executing a test and closing it after the test is completed, independently of the status of the test.
The initialization of the Spark context consist of specifying the configuration for the sequence of tests. Some of these parameters can be dynamically defined through a simple parameterization. The context is created only if it is not already defined within the scope of the test using the getOrCreate method.
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 trait SparkContextWrapper { protected[this] var sc: SparkContext = _ def getContext: SparkContext = { val conf = new SparkConf().setAppName(s"Test-App") .set("spark.executor.instances", "2") .set("spark.driver.memory", "2g") .set("spark.executor.memory", "2g") .set("spark.executor.cores", "2") .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") .set("spark.rdd.compress", "true") .set("spark.shuffle.spill", "true") .set("spark.shuffle.spill.compress", "true") .set("spark.shuffle.memoryFraction", "0.4") .set("spark.io.compression.codec", "snappy") .set("spark.network.timeout", "600") sc = SparkContext.getOrCreate(conf.setMaster("local[4]")) sc.setLogLevel("ERROR") sc } def close: Unit = { if (sc != null) sc.stop } }

The solution is to let ScalaTest method manage the lifecycle of the Spark context for testing.
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 trait SparkContextForTesting extends SparkContextWrapper with BeforeAndAfterAll { self: Suite => override def beforeAll: Unit = { getContext super.beforeAll } override def afterAll: Unit = { close super.afterAll } }

Note: The BeforeAndAfterAll trait can only be sub-classed by a test suite inheriting the Suite trait. The method beforeAll (line: 5) is automatically called before the first test of your test suite and the method afterAll (line 10)is called after your last test is completed, whether those tests succeeded or not

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class MyTest extends FlatSpec with Matchers with SparkContextForTesting { val x: Int = -4 it should "My first test" in { val sqlContext = new SQLContext(sc) // .... } // ... other tests it should "My last test" in { // clean up after it completes } }

As they say at the end of the movie, "That's all folks!"

Reference
ScalaTest User Guide


text:
Public Group

# ID3DXFont rect calculation issue

This topic is 3478 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I made a method to calculate the size of the rect used to render some text, however for some reason the size it returns is diffrent from the size used when rendering the text for real :( Looking at the actaul size of the area the text is rendered to and the size returned it appears my calc rect method is adding an extra line break after the first word...
//the draw method
void Font::DrawWidth(Point2<float> pos, unsigned width, const std::wstring &text, Align align, unsigned col)
{
RECT rect;
rect.top = (long)pos.y;
unsigned flags = DT_NOCLIP | DT_WORDBREAK;
switch(align)
{
case IFont::CENTRE:
rect.left  = (int)pos.x-width/2;
rect.right = (int)pos.x+width/2;
flags |= DT_CENTER;
break;
case IFont::RIGHT:
rect.right = (int)pos.x;
rect.left = (int)pos.x-width;
flags |= DT_RIGHT;
break;
case IFont::LEFT:
default:
rect.left  = (int)pos.x;
rect.right = (int)pos.x+width;
flags |= DT_LEFT;
break;
}
if(FAILED(font->DrawTextW(
0, text.c_str(),
text.length(), &rect, flags, col)))
throw exception::Error(L"Failed to draw text");
}
//the calcu size method
Size2<> Font::CalcSizeWidth(unsigned width, const std::wstring &text, Align align)
{
RECT rect = {0,0,width,0};
unsigned flags = DT_NOCLIP | DT_CALCRECT | DT_WORDBREAK;
switch(align)
{
case IFont::CENTRE:
flags |= DT_CENTER;
break;
case IFont::RIGHT:
flags |= DT_RIGHT;
break;
case IFont::LEFT:
default:
flags |= DT_LEFT;
break;
}
if(FAILED(font->DrawTextW(
0, text.c_str(),
text.length(), &rect, flags, 0)))
throw exception::Error(L"Failed to calc text size");
return Size2<>((float)rect.right-rect.left, (float)rect.bottom-rect.top);
}

When testing with the string "Multiple lines of text." and a width of 150 the actual text is less lines and wider than the calcuated size. -actaul text layout
Multiple lines of
text.

-how the calc method appears to be laying it out
Multiple
lines of
text.

##### Share on other sites
Still havnt solved this...I cant see anything wrong with my code, is it an issue with CALCRECT or something? If so is there some work around as I really need to reliabley determin the size of the area the text will be rendered too...

##### Share on other sites
If I remember correctly when I was using DX's font helpers it uses the corner of the RECT as a starting position. It doesn't force the text to remain within the RECT. I could be wrong, but, if my memory serves me correctly...

##### Share on other sites
Are you certain that it should fit within 150 pixels exactly how you imagine it? If you input a width of say, 500, does it fit all in one line?

I'm not sure on your methodology and why you're attempting it render text the way you are. Are you trying to make something that will automatically adjust for everything? I can't think of a time that you wouldn't want to specify the width of a text you're rendering (assuming its multiple lines).

##### Share on other sites
Quote:
 Are you certain that it should fit within 150 pixels exactly how you imagine it? If you input a width of say, 500, does it fit all in one line?

I didnt imagen anything. The size returned by the calc method is simply diffrent from the size of the area the text is actaully rendered too with DrawWidth

Quote:
 I'm not sure on your methodology and why you're attempting it render text the way you are. Are you trying to make something that will automatically adjust for everything? I can't think of a time that you wouldn't want to specify the width of a text you're rendering (assuming its multiple lines).

I'm simply trying to determin how much space the rendered text will take which has many applications.

For example ensureing that the dialogs in my game are large enough for the text to fit on them (the dialogs have a fixed width of 80% the window width, hence using the CalcWidth version which accepts a fixed width as its argument, so the text will expand vertically onto however many lines it needs.)

Ive added a sample of the problem below
	//calc the area the text is rendered too	Size2<> size = fontB->CalcWidth(150, L"Multiple lines of text.");	//draw the area as the background	primitive::DrawRect(primVb.ptr(), Point2<>(50,100), size, 0xFFFF8000);	//mark where 150 pixels is past 50 (ie 200)	primitive::DrawLine(primVb.ptr(), Point2<>(200,100), Point2<>(200,150), 0xFFFF0000);	//render the actaul text	fontC->DrawWidth(Point2<>(50,100), 150, L"Multiple lines of text.");

##### Share on other sites
Ah, well you can use a different function for that GetTextExtentPoint32.

I make use of this for position messages like Author: text messages which use different colors. However, I do not use this for rendering text within a menu. I am confused because I cant imagine when you'd want to do this (aside from the height, maybe, but there are better solutions to that even) with menus.

A menu should have a position (x,y) and a width/height to them. So when you want to check for the width of your rect to draw, it should be 80% of your menu width, and likewise any rules you have for heights. You do not need to compute all this extra stuff. Simply but the bottom of the rect at the desired level and it will not render text beyond that point (not sure if you need to remove the NOCLIP flag).

For example:
int x = menu.x + menu.width * 0.1f;int y = menu.y + 15; //for the title, whatever size you needdrawText(x, y, menu.width * 0.8f, "hey this is a string!");

1. 1
2. 2
3. 3
Rutin
18
4. 4
JoeJ
14
5. 5

• 14
• 10
• 23
• 9
• 47
• ### Forum Statistics

• Total Topics
632636
• Total Posts
3007574
• ### Who's Online (See full list)

There are no registered users currently online

×

format: plain


text:
Select Page

Understand the problem

Find all integer solutions $(a,b)$ of the equation$\$(a+b+3)^2 + 2ab = 3ab(a+2)(b+2)\$$

Source of the problem
Costa Rica NMO 2010
Number Theory
6/10
Suggested Book
A Friendly Introduction to Number Theory by J.H.Silverman

Do you really need a hint? Try it first!

Write the equation in this form : $(a-b)^2 = 3(ab-1)(ab+2a+2b+3)$ The idea is that the RHS is a 4 degree polynomial in two variables and the LHS is a 2 degree polynomial in the same two variables. Now, you have the intuition that the 4th-degree polynomial will surpass the LHS after some time. We, therefore, aim to bound the a and b assuming the equality holds.

So, we try to find when RHS $\geq$ LHS.  Rather we will find the condition when $(a-b)^2 \leq (ab-1)(ab + 2a + 2b + 3)$. Assume $a \geq b$. We will find when $latex (a-b) \leq (ab-1)$ and $(a-b) \leq (ab + 2a + 2b + 3)$.

$latex (a-b) \leq (ab-1)$ – For this to hold. $(a^2-1)(b^2 -1) \geq 0$. $(a-b) \leq (ab + 2a + 2b + 3)$ – For this to hold $(a+3)(b+1) \geq 0$.

Hence, try to understand that we have essentially bounded the solutions. Observe this implies that to solutions to have essentially. $latex -3 \leq a,b \leq 1$. Hence show that by computation that : The solution set is  $\boxed{(-3,-3), (-3,0), (0,-3), (-2,1), (1,-2), (-1,-1), (1,1)}$

Connected Program at Cheenta

Math Olympiad is the greatest and most challenging academic contest for school students. Brilliant school students from over 100 countries participate in it every year. Cheenta works with small groups of gifted students through an intense training program. It is a deeply personalized journey toward intellectual prowess and technical sophistication.

Similar Problems

Squares and Triangles | AIME I, 2008 | Question 2

Try this beautiful problem from the American Invitational Mathematics Examination I, AIME I, 2008 based on Squares and Triangles.

Percentage Problem | AIME I, 2008 | Question 1

Try this beautiful problem from the American Invitational Mathematics Examination I, AIME I, 2008 based on Percentage. you may use sequential hints.

Smallest Positive Integer | PRMO 2019 | Question 14

Try this beautiful problem from the Pre-RMO, 2019 based on Smallest Positive Integer. You may use sequential hints to solve the problem.

Circles and Triangles | AIME I, 2012 | Question 13

Try this beautiful problem from the American Invitational Mathematics Examination I, AIME I, 2012 based on Circles and triangles.

Complex Numbers and Triangles | AIME I, 2012 | Question 14

Try this beautiful problem from the American Invitational Mathematics Examination I, AIME I, 2012 based on Complex Numbers and Triangles.

Triangles and Internal bisectors | PRMO 2019 | Question 10

Try this beautiful problem from the Pre-RMO, 2019 based on Triangles and Internal bisectors. You may use sequential hints to solve the problem.

Angles in a circle | PRMO-2018 | Problem 80

Try this beautiful problem from PRMO, 2018 based on Angles in a circle. You may use sequential hints to solve the problem.

Digit Problem from SMO, 2012 | Problem 14

Try this beautiful problem from Singapore Mathematics Olympiad, SMO, 2012 based on digit. You may use sequential hints to solve the problem.

Problem on Semicircle | AMC 8, 2013 | Problem 20

Try this beautiful problem from AMC-8, 2013, (Problem-20) based on area of semi circle.You may use sequential hints to solve the problem.

Radius of semicircle | AMC-8, 2013 | Problem 23

Try this beautiful problem from Geometry: Radius of semicircle from AMC-8, 2013, Problem-23. You may use sequential hints to solve the problem.


text:
# Different ways to sort a counter in Python

#### Software Engineering Python

Get FREE domain for 1st year and build your brand new site

The different ways to sort a counter in Python are:

• Using the Counter.most_common([N]) method
• Using .sorted() to sort just the keys
• Using .sorted() to sort values on the given (key,value) pairs

The official python document defines a counter as follows:

“A Counter is a dict subclass for counting hashable objects. It is an unordered collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. ”

Syntax:

class collections.Counter([iterable-or-mapping])

## Sorting Counters

Counters are very useful as is, with the added functionality of easy sorting ,it saves so much time and avoids reinventing the wheel. So the next time you need to sort a counter just refer to this article to know everything there is to it.
In the methods mentioned below, I've explained how to use some built-in python functions along with their time complexities so you can choose which ever is suitable to your application.

Here are the different ways of sorting a counter:

1.Using the Counter.most_common([N]) method
2.Using .sorted() to sort just the keys
3.Using .sorted() to sort values on the given (key,value) pairs

1. Using the Counter.most_common([N]) method
It essentially returns a sorted list of the counts from the most common element to the least common element in the counter. If N is omitted it returns all elements in the counter and if N is mentioned it returns only the first N elements of the returned list. Elements with equal counts are ordered arbitrarily.

Syntax:

Counter_object.most_common([n])

Time Complexity:

If N value is omitted: Θ(n log n)
If the N value is greater than 1: Θ(n log N)
Where n is the number of entries in the counter

Example Code Snippet where N value is not mentioned:

from collections import Counter
x = Counter({'a':5, 'b':3, 'c':7})
print(x.most_common())
-->[('c', 7), ('a', 5), ('b', 3)]

Example code snippet where N value is mentioned:

x.most_common(1)
-->[('c', 7)]

If you ask for a Top N instead of all values, a heapq is used instead of a straight sort.

1. Using .sorted() to sort just the keys
The .sorted() method is used to sort any iterable.It always returns a sorted list

Syntax:

sorted(iterable, key=None, reverse=False)

Time Complexity:
Both,average and worst case complexities:Θ(n log n)
Where n is the number of entries in the counter

Here the iterable is the counter object.Key takes a function for sorting. Here we've used .get to sort by the values in the counter object. Reverse is an optional parameter.If not mentioned it will sort in ascending order. I mentioned it'll sort in descending order.
This method would give you the same result as x.most_common(), but only return the keys, for example:

from collections import Counter
x = Counter({'a':5, 'b':3, 'c':7})
sorted(x, key=x.get, reverse=True)
['c', 'a', 'b']

1. Using .sorted() to sort values on the given (key,value) pairs
Here I've used the same method as in method 2 but returning both the key as well as the values. The iterable passed here iterates through all the (key,value) pairs and sorts them according to their values.
sorted(x.items(), key=lambda pair: pair[1], reverse=True)
[('c', 7), ('a', 5), ('b', 3)]

With this article at OpenGenus, you must have the complete idea of Different ways to sort a counter in Python. Enjoy.

#### Riddhi Athreya

Student at Dayananda Sagar College of Engineering

Improved & Reviewed by:


text:
# Differences

This shows you the differences between two versions of the page.

Line 13: Line 13:
**Coordinates**: 36° N, 30° W\\ **Coordinates**: 36° N, 30° W\\

\\ \\
Line 23: Line 23:

\\ \\


text:
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Analysis of Variance in R, You will be able to identify reasons for employing an Analysis of Variance (or ANOVA) test in your data analysis after completing this tutorial.

You’ll also learn how to analyze the findings of an ANOVA f-test.

Let’s imagine you want to look at a category variable and see how it relates to other variables.

Take, for example, the Airline dataset.

Plot Differences in Two Measurements-Bland-Altman Plot in R »

library(tidyverse)
library(dplyr)
library(ggplot2)
head(data)

“How do different categories of the reporting airline feature (as a categorical variable) affect flight delays?” is a question you might wish to consider.

The ANOVA method can be used to evaluate categorical variables like “Reporting_Airline.”

ANOVA can be used to determine the relationship between two groups of a categorical variable.

You may use ANOVA to see if there is any difference in the average flight delays for the different airlines in the Airline dataset.

How to Perform Dunnett’s Test in R » Post-hoc Test »

### Step 2: Null Hypothesis

As a result, the null hypothesis for ANOVA is that the mean (the reporting airline’s average value) is the same for all groups.

The alternate or research hypothesis is that the average for all groups is not the same.

Here we are going to explain two group cases, a comparison between AA vs AS and AA vs PA (1).

In the first case, the null hypothesis is that the mean values of ‘AA’ and ‘AS’ are the same, while the alternative hypothesis is that they are not.

The F-test score and the p-value are returned by the ANOVA test.

The F-test determines the ratio of the variance between the mean of each sample group and the variation within each sample group.

The p-value indicates whether or not the outcome is statistically significant.

In general, you can consider a variance to be statistically significant if the p-value is less than 0.05.

The association is substantial if the F-test score is high and no association if the F-test score is low.

Repeated Measures of ANOVA in R Complete Tutorial »

### Step 3: ANOVA comparison

The aov() function in the stats package can be used to perform the ANOVA test.

data1<-data %>%
select(ArrDelay, Reporting_Airline) %>%
filter(Reporting_Airline=='AA'|Reporting_Airline=='AS')
AOV<-aov(ArrDelay~Reporting_Airline,data=data1)
summary(AOV)
Df    SumSq MeanSq Fvalue Pr(>F)
Reporting_Airline    1     126   125.7    0.13  0.718
Residuals         1139 1097707   963.7

It calculates the ANOVA results once you enter the arrival delay data of the two airline groups you want to compare.

Because the F-test score of 0.13 is less than 1 and the P-value is greater than 0.05, the prices between “AA” and “AS” are not significantly different.

How to Perform Tukey HSD Test in R » Quick Guide »

A similar analysis can be used to “AA” and “PA (1).”

data1<-data %>%
select(ArrDelay, Reporting_Airline) %>%
filter(Reporting_Airline=='AA'|Reporting_Airline=='PA (1)')
AOV<-aov(ArrDelay~Reporting_Airline,data=data1)
summary(AOV)
Df  Sum Sq Mean Sq F value   Pr(>F)
Reporting_Airline    1   24008   24008   17.95 2.45e-05 ***
Residuals         1127 1507339    1337

Because the F-test score of 17.95 is quite high and the P-value is 0.0000245, which is less than 0.05, the flight delays between “AA” and “PA (1)” are significantly different.

Because the ANOVA test produces a significant F-test score and a small P-value, you can conclude that there is a strong association between a category variable and other factors.

You learned that an ANOVA test can be used to identify correlations between distinct groups of a categorical variable and that the F-test score and p-value can be used to identify the statistical significance.

Kruskal Wallis test in R-One-way ANOVA Alternative »

The post Analysis of Variance in R: 3 Steps appeared first on finnstats.


text:
# Pale Lager

The color of pale lager ranges from light bronze to nearly transparent and the alcohol anywhere from 4-6%. Adjunct usage may be quite high, though in some cases the beer is all-malt. Carbonation is typically forced, though not always. One thing that does not vary is that neither the malt nor the hops make much of an impression on the palate. These beers are brewed for minimum character, though faint traces of hop or malt may show through. Commonly detected features and flaws include fusels, oxidized malt and skunked hops. The body will often be thin and/or spritzy while the finish is typically mildly bitter.
• from \$3.50

from \$3.50
Sold out


text:
## Cryptology ePrint Archive: Report 2014/653

Mersenne factorization factory

Thorsten Kleinjung and Joppe W. Bos and Arjen K. Lenstra

Abstract: We present work in progress to fully factor seventeen Mersenne numbers using a variant of the special number field sieve where sieving on the algebraic side is shared among the numbers. It is expected that it reduces the overall factoring effort by more than 50\%. As far as we know this is the first practical application of Coppersmith's factorization factory'' idea. Most factorizations used a new double-product approach that led to additional savings in the matrix step.

Category / Keywords: implementation / Mersenne numbers, factorization factory, special number field sieve, block Wiedemann algorithm

Original Publication (with minor differences): IACR-ASIACRYPT-2014

Date: received 22 Aug 2014, last revised 12 Jan 2015

Contact author: akl at epfl ch

Available format(s): PDF | BibTeX Citation

Short URL: ia.cr/2014/653

[ Cryptology ePrint archive ]


text:
Authors: Cabezas, Carlos; Daly, Adam M.; Endo, Yasuki

Journal: SPECTROCHIMICA ACTA PART A-MOLECULAR AND BIOMOLECULAR SPECTROSCOPY

Publication date: 2021/11/05

DOI: 10.1016/j.saa.2021.119945

Abstract: The reaction system between the simplest Criegee intermediate, CH2OO, and the greenhouse gas CO2 has been investigated by Fourier transform microwave spectroscopy. The CH2OO-CO2 weakly bound complex was identified in the rotational spectrum, where inversion doublets due to the tunnelling motion between two equivalent configurations of the complex, with CO2 located at one side or the other side of the CH2OO plane, were observed. Using a two-state torsion-rotation Hamiltonian, a complete set of rotational and centrifugal distortion constants for both tunneling states were derived. In addition, the torsional energy difference between both states could be accurately determined, being 23.9687 MHz. The non-observation of the cycloaddition reaction product is in agreement with our ab initio calculations and with previous results that concluded that the reactivity of CIs toward CO2 is measured to be quite limited. (C) 2021 The Author(s). Published by Elsevier B.V.


text:
# $n$ couples crossing a river

There are $n$ couples on one side of the river. Nobody is on the other side. They have a boat that accommodates up to 2 people. For every trip across, someone(s) must bring the boat back as well. The aim is for all of them to cross the river.

There is one important rule:

No woman can be left (in the boat or either shore) with a man, unless her husband is also present.

There are no tricks, such as divorcing during the game, etc.

Give a formula to find the minimum number of boat trips required.

• If "left alone" means they are the only two people in one place, then the rule needs rephrasing. Apr 2, 2015 at 11:59
• The rule should be rephrased either way. The only way a woman can be "left alone" with a man and have her husband present is if her husband is that man. The way it is worded seems to imply that a woman cannot be "left anywhere" with a man (regardless of how many men/women are present) unless her husband is present, even though it states the other. Apr 2, 2015 at 17:37
• So basically, all women must be in a group composed either solely of women, or including her husband? Apr 2, 2015 at 20:18
• Can we reverse the genders in this puzzle so it's not yet another case of classic sexism you always see in logic/philosophy books/courses/instructors? Apr 4, 2015 at 15:05
• @ghosts Not sure why you said it doesn't make sense the other way around... both the puzzle and the implied lack of trust are isomorphic to the gender-flipped version. Apr 6, 2015 at 13:20

Note: This answers the question before the question was changed from "left alone ... with" to just "left ... with".

Definitions:

• trip across means going from the original side to the destination side

• woman left alone with a man means those individuals are the only two people in that place.

Send all the women across first. This requires $n-1$ trips, leaving the boat at the destination. One woman (call her W) returns.

Send all the men across. This requires $n-1$ trips, leaving the boat at the destination. W's husband returns and both go across (1 trip).

Total $2n-1$ trips across to the other side. Each trip across is matched with a trip back except for the last trip across, so we have $4n-3$ river crossings.

In the first phase, every woman is in the company of either only women or with her husband. In the second phase, W remains with her husband or is alone, and all other women are with at least the number of people they were with in the first phase.

This is minimal since each pair of river crossings can deposit only 1 person at the destination if someone must return with the boat. After $2n-2$ pairs of river crossings (and hence $2n-2$ trips across), only 2 people remain on the original side. They take the final trip across to total $2n-1$ trips across.

With the reworded question, we can still have the same number of river crossings with a different order.

The "left with" rule is taken to mean that a woman can be in a boat on her own or with another woman, or on a shore with her husband (or with only women). In particular, a woman is permitted to cross to the shore opposite her husband's, provided she does not disembark and provided she returns with another woman.

Pair each man $M_i$ with his wife $W_i$ for $i \in [1,n]$. Starting with $i=1$ and working through to $i=n$, send $M_i,W_i$ across, $W_i$ returns, picks up $W_{i+1}$ and goes across again. Then $W_{i+1}$ returns.

Each trip across deposits one person, so we still have $2n-1$ trips across and $4n-3$ river crossings.

• so if there are 5 couples, according to you it will take $2*5-1=9$ trips. But with each trip you can actually only drop 1 person to the other side, because somebody has to bring the boat back, so in 9 trips you can get at most 6 people on the other side. What about the other 4? Apr 2, 2015 at 21:00
• @Novarg that is not what he is saying. He is saying it takes 2*5-1 trips from the starting point to the destination (which is technically what it sounds like the question is asking for?) and 2*5-2 trips in the other direction... Apr 2, 2015 at 21:04
• @Novarg Warlord 099 is correct - I took the term 'trip across' in the question to mean something different from 'back'. I used the term 'river crossings' to include both. Apr 2, 2015 at 22:35
• I've edited my answer to show formulas for both 'trips across' and 'river crossings'. Apr 2, 2015 at 22:55
• @Lawrence, oh, ok. My bad. Here's your +1 :) Apr 3, 2015 at 5:28

One way to keep couples together would be this process:

Husband A ferries Wife A.
Husband B ferries Husband A.
Husband B ferries Wife B.
Husband C ferries Husband B.
Etc.

So, the only time a woman is alone with a man is:
On the far shore, Wife A and Husband A.
On the near short, Wife N and Husband N, before Husband N ferries Husband N-1.
On the boat, each wife is ferried by their husband.

As for total trips, there are $4n-3$ total trips across.

Edit: Surprisingly, if we reverse the genders for the solution, the clause about women being without their husbands is fulfilled.

• When Husband B is ferrying Husband A, Wife B is 'left with' husband C, etc without Husband B present. Apr 4, 2015 at 16:42

When there are X couples on the left and Y couples on the right, with boat on the left:

• Couple A cross from left to right.
• Husband A gets out, Wife A goes back.
• Wife B gets in boat with Wife A. Both cross.
• Wife A gets out, now with her husband.
• Wife B goes back.

We now have X-1 couples on the left and Y+1 couples on the right, and at no time was any woman left with a man, but without her husband. There are moments when a boat arrives that a woman is in the boat and her husband is on the far shore, but she remains in the boat with no man in the boat with her.

Repeat the process X times. When there is only one couple on the left, they cross and the process is done; no one goes back.

This takes N-1 (round) trips, which has to be the minimum. Each trip to the right takes two people (the maximum) and each trip to the left takes one (the minimum). This would be the minimum number of trips necessary if there were no restrictions on who could be left with whom.

• Technically speaking it would take N-2 round trips and 1 one-way trip. N-1 round trips would leave you with the boat and a minimum of one person back on the original shore. Apr 7, 2015 at 18:28


text:
Personally, I just really have owned a lot of bike lights. Starting with the Light & Motion NiMH Metal ARC that weighed in at over three pounds, but over the last 20 years, things have really stabilized around LED lights and they are small and lightweight, so here are some recommendations:

1. Garmin Vario UT 800 Light and RTL 515 Radar. OK, if you are bicycling nut, then if you have bike computer, these are the ones to get. They turn on and off depending on motion and the rear system has a radar in it and it shows on your bike's computer. I haven't ridden outside very much, but while heavy, they are very bright. There is a new radar with a camera, but the RTL 715 is way bigger and bulkier. Also these days, you don't need the UT800 as there are lots of ANT+ compatible lights, but the mount is nicely integrated with the Garmin mount. Today, I actually run a Karoo 2 with the Garmin adapter and this works well. The Radar is expensive at $150, but the regret factor is high when someone runs you over. 2. NiteRider Lumina 750. If you don't need a bike computer, then you don't need to spend as much. Outdoor Gear Labs is pretty reliable and likes the Lumina 750 as a front-mounted light and it is just$70 unlike the Garmin combination above but those reviews are four years old from 2018.
3. Bontrager Ion 200 and Flare RT. Bicycling Magazine has a much newer 2020 review and for daytime, they like this front and rear light, they aren't smart, but they sure are small for $130. These are also ANT+ compatible so they will work with your computer. 4. Ascher USB Rechargeable. Hey at$16 for a set, these are cheap and disposable, so good if it's really a bike you don't care that much about.
5. NiteRider Lumina OLE 1200 Boost. Insanely expensive at $170, but it is a full 1,200 lumens at a maximum setting which is basically like the sun and two hours in normal use. # Helmet Lights and Smart Helmets 1. Light & Motion Vis 360. One of my favorite lights is the dedicated helmet light because it has both a front and rear and you can run it on your helmet so you don't forget it. 2. Smart Bicycle Helmet. OK, I have not tried this, but I really do want to, rather than a clumsy strap-on thingy, it integrates the lights directly into the helmet. It does mean that when the light fails, you need a new helmet, but the visibility is excellent. 3. Lumos Ultra has front and rear lights and senses left and right turns so has turn signals is a Kickstarter project for$120 and can even have MIPS internal wrap (for an extra \$10). There were on Kickstarter and seem to have delivered successfully with good reviews. What's amazing is that with COB (chip on board), the weight penalty is minimal, it is just 370 grams. My current helmet the Kask Protone is great and light at 260g and is 280g for a Large and the Vis 360 is definitely another 100g. And with MIPS it is 414 grams which is really not bad as this is more protection. And if you want to get a skateboarder urban combat look, then the Lumos Matrix is huge with a gigantic LED light on the back.

#### Related Posts

This site uses Akismet to reduce spam. Learn how your comment data is processed.


text:
# No offense intended, but…

I haven't been a member on here for all that long of a period of time, but I would like to point out some things that I have observed that some may be overlooking. I have visited the site a large number of times before joining I would like to mention as well.

First of all, from the comments to most of the posts I have seen over the last couple of days on meta, nobody really wants to see anything from anyone new on MSE. Some are belligerent about it while a few others are perhaps less aware of their attitude, but it exists. I came here because I was already in the stack exchange community, a cross affiliation from my time I spend working with Ubuntu. I am also an applied math major and at my school that means taking grad classes regularly, so I'm not that far down the totem pole in that respect either. There seems to be alot of bitterness, especially regarding the homework problems situation. While I understand that many people may be looking for a handout it is unfair to assume that is the case for anybody asking a homework question, or help understanding or clarifying some aspect of a particular area. Some people do make an effort, just saying. Call me crazy, but I kinda feel unwanted here, and I may be, in which case I will gladly leave. MSE should be as much about camaraderie as about solving particular problems. I have seen many of my own friendships grow with peers as we explore some particular problem together. I would suggest that perhaps as a community, more "communing" could be done.
Anyways, if you read this far thanks, hope you'll consider what I've said if you've unfairly been a jerk to someone who didn't deserve it recently.

• Your observation about "alot of bitterness" is correct. This is a function of time, so there's hope it reached its maximum already and will decay over time. ¶ I don't see why you personally feel unwanted, though. Clicking through to your main site activity, I found one question, which already had an upvote from me and was in my "favorites". (I tend to mark questions as favorites and then hope someone else answers... I'm lazy like that.) – 75064 May 5 '13 at 4:24
• It is basic etiquette all over the world that when a stranger asks you a question, the reply should begin with some variation on the words "what have you tried?", "is this homework?", "what are your thoughts?", CLOSED, "do your own work", "you have not met our quality standards", or "mend your ways or don't come back". People on MSE sometimes forget that. If only those greetings were used more often, I think everyone could feel right at home. – zyx May 5 '13 at 6:37
• And, of course, to get help from your professor, you should walk into his office, place your homework sheet in front of him, and silently wait for him to give you the answer. – Hurkyl May 5 '13 at 12:17
• @zyx Do you know the feeling when you are at a party, nipping beer and a stranger approaches you and says to you "Prove that every continuous function from the closed unit interval to the reals is uniformly continuous." What do you do in these situations? – Michael Greinecker May 5 '13 at 13:23
• I have no problem with people asking OPs "what have you tried". I just wish they would do this more politely! (I find copied-and-pasted comment rude, but it is better than just silently closing the question...) – user1729 May 5 '13 at 13:41
• I should also say that I regularly recommend my students to ask their question here. They do not want to because they see the community as too snobbish. I think we have a problem... – user1729 May 5 '13 at 13:53
• In particular, the "does not meet our quality standards" comment makes me shudder, partly because of the bureaucratese, but mainly because it could be interpreted as speaking for me. – André Nicolas May 5 '13 at 15:09
• @user1729 That does sound like a problem. Here's a possible fix: suggest that they answer 2-3 questions before posting their first question. Nobody tells WHYT to answerers, and in the process they will get used to the site and also get rid of the rep=1 indicator. Answering questions here may be more useful anyway. ¶ #Tristen: Since your profile says "send me a line", I'll point out that SE sites have no direct messaging feature, and the email address you entered is not shown to other users. So, if no SE users ever contact you directly, it's not necessarily because they are antisocial. – 75064 May 5 '13 at 15:13
• @user1729: I see your problem. But this is the way internet forums work. Whichever forum you join, you are well advised to lurk for a little while. Then you will learn about "house rules" and about the way the regulars post. If you just "crash the party", you may easily cross a few lines, and it makes sense that the regulars will let you know about your faux pas! I know that there are many "anything goes" chat forums in the web, but Math.SE is not one of those. I kind of like it that way. – Jyrki Lahtonen May 5 '13 at 16:04
• @JyrkiLahtonen I understand this, and I too like the rigid structure of MSE. I initially was surprised when my students told me that they were afraid to come here, but when I thought about it a bit more then I began to understand why. I do not think the structure is the problem. Personally, I think the site is too harsh to those coming here. My view of MSE is of a lecturer's or professor's office hours. In such situations the student has obligations but so does the professor. They should be polite and helpful, and so on...(cont.) – user1729 May 5 '13 at 16:19
• ...and I wonder if MSE comes across as the professor who is unwilling to answer questions unless they are of a sufficient difficulty, or the professor who is constantly looking down his nose at students...I dunno. I cannot quite put my finger on anything specific, but taking a step back I think I can understand my students fears and reservations about this site. – user1729 May 5 '13 at 16:20
• The difference is that when visiting a professor's office, you know who's gonna answer. Here it may be one of the bullies among upper classmen looking for his breakfast victim. I don't know the ideal way of resolving this, and my own feelings about this are continuously swinging. The resentment towards copy/pasted questions is genuine. May be it is also about fear? Fear of the site that was once largely populated by people taking math seriously becoming overrun by a horde. More advanced questions getting buried under the pile of calculus questions? – Jyrki Lahtonen May 5 '13 at 16:33
• @Jyrki: I have no trouble finding more questions that interest me and require non-trivial effort than I have time to think about — and being retired, I’ve lots of time to think about them. – Brian M. Scott May 5 '13 at 18:23
• @zyx Faculty are obliged to help their students; they are paid for it. SE network has no obligation to publish user-contributed content, such as questions. Their stated goal is to "build libraries of high-quality questions and answers". SE leaves the determination of what is a high-quality question to the members of each SE community. The members may reasonably decide that, e.g., "Find the inverse Laplace transform of $(3s+4)/(s^2-9)$" is not a high-quality question, and should not be included in the library. This is why they are given closing&deletion tools by SE. – 75064 May 5 '13 at 22:38
• Whenever I'm new to any site I do a whole ton of reading before I do very much writing at all. Every site is a community, like a bunch of friends. There are inside jokes, ways of talking, etc. The best way to get involved is to watch and listen, then contribute when you know you have something new and valuable to contribute. On a site like this that means a lot of searching to see if someone has already asked an equivalent question or given a better answer. It's not just Math.SE that can seem cold to newcomers. Most forums I read are like that. – Todd Wilcox May 14 '13 at 19:44

## 5 Answers

Some people do make an effort, just saying.

This -- along with some means of actually making this visible in one's question -- is all people have been asking for. We (meaning the "bitter" people) want people to ask questions like this, rather than like this.

The bitterness you refer to is that there has been a recent upheaval where it was realized that there's enough support for the opinion that we've allowed far too much junk on MSE to break the long-standing deadlock versus the opinion we want everything on MSE, and that didn't go pleasantly.

And so we're still in a transition period in the wake of that argument. I expect things to settle down as people get more acclimated to the change and can devote more effort towards working out the nuances of which questions require action and what that action should be.

• Students can get stuck and have no idea how to proceed. For those who have been doing this a while, the idea of using a contour integral to find a Fourier Transform is almost second nature. However, for those just starting out, a gentle hint is all that is needed to answer the second question. Once they have tried the contour integral, they might amend their question with more specific difficulties. – robjohn May 5 '13 at 16:42
• That's quite a self-serving summary of the "recent upheaval", but even if correct, the fact of a transition period (which I agree is taking place, at least on some matters) would suggest allowing the transition to take effect on its own and not posting threads whose apparent intent is to manipulate moderator elections. – zyx May 5 '13 at 20:10
• @zyx: "threads whose apparent intent is to manipulate moderator elections"... what are you smoking and where can I get some? – Willie Wong May 6 '13 at 8:57
• @Willie: I’m not convinced that this question was posted with conscious intent to manipulate the moderator elections, but it is certainly open to that interpretation and could have that effect whether intentionally so or not. – Brian M. Scott May 6 '13 at 12:24
• How is discussing whether something ought to be a topic for an election "manipulating" that election? Manipulation has a distinct negative connotation here (as in, involving methods that either due to legal or ethical reasons ought not be used). – Tobias Kildetoft May 6 '13 at 13:29
• @Tobias: If you read the comments over there, you know the answer to your question. If you didn’t, your question is premature. (Whether you agree with those comments is a separate issue.) – Brian M. Scott May 6 '13 at 13:34
• @BrianM.Scott I have been reading the comments. And I don't disagree that the thread seems like an attempt to influence the election. But to me, using the word manipulation carries an implication of wrongdoing to some extend. – Tobias Kildetoft May 6 '13 at 13:39
• @Tobias: I think that zyx intended the negative implication, and I think that it’s defensible, though — as I said in my comment — I’m not convinced that it’s correct. – Brian M. Scott May 6 '13 at 13:43
• (Are we getting derailed here?) TBH, I'm not even sure exactly what I'm supposed to be accused of, and haven't been particularly inclined to humor zyx and prompt for clarification. The (intended) extent of my "manipulations" was to throw out the idea of separating the moderator election from the PSQ topic(s), after having developed a concern that being a recent hot-button topic might cause it to influence the elections more than it actually deserves, and am surprised at the apparent negative reaction (unrelated (?) to zyx's accusations) to what I actually stated along those lines. – Hurkyl May 6 '13 at 18:13
• @BrianM.Scott: I thought zyx was referring to this post here. If that's what he/she intended, it would've been clearer had he/she linked to the thread being referred to. – Willie Wong May 7 '13 at 7:34
• @WillieWong, I spoke of "posting threads" which in SE parlance means addition of new questions to the meta. So it seemed clear enough that it refers to something beyond this answer (which is also troubled, as it pre-empts large swaths of the discussions on meta by smugly declaring everything to have been settled, with only a few minor details left to be arranged). If you no longer stand behind your first inflammatory comment, you have the power to edit or delete it. It doesn't matter all that much how the comment votes go, but trolling for "this guy is crazy" upvotes doesn't help anything. – zyx May 8 '13 at 19:51
• @BrianM.Scott, I thought of explaining the remark with an answer in the other thread, but lacked the time and inclination. If this comment discussion is an indication of interest I might do it. The present answer is worse in some ways, and probably more worthy of comment, but is not out of line with the way site works. – zyx May 8 '13 at 22:12

I browsed the list of new users and took a look at how they were received. Most did not post anything yet, but almost all of those who did received non-negative scores, and more often than not, answers. Even some less-than-stellar questions such as Find Laplace Transform of the function were answered. One question was downvoted and then upvoted twice: How can a matrix be Hermitian, unitary, and diagonal all at once

On the first two pages of "New Users" list I found just one user whose question was downvoted and closed (link removed, since the question was reopened).

Overall, I think the treatment of new users is not as rough as it appears from your post. (I admit that I have no data regarding unregistered users, who do not appear in the list.)

MSE should be as much about camaraderie as about solving particular problems. I have seen many of my own friendships grow with peers as we explore some particular problem together. I would suggest that perhaps as a community, more "communing" could be done.

Here I disagree. First of all, SE is not a social network. Even so, there is quite a bit of socializing going on in the main chat room, and it seems that a number of frequent users maintain contact via non-SE tools (facebook, email, skype, etc). Given that the channels for networking are so plentiful, it should be easy for us to stick to math on the main site.

• The rest of your points are fine, but I disagree about the last paragraph. Math.SE is very much about social networking. At least for me (I don't have a facebook account and don't plan to get one). – Jyrki Lahtonen May 5 '13 at 9:43
• The community sense should extend from the common bond of interest in mathematics. – Tristen May 5 '13 at 11:07
• I agree with your last comment. However, I actually disagree with your assessment of how new users are treated. Specifically, with regards to the question you cite which was downvoted and closed. Currently, the time stamps are: Question posed (10 hours ago). OP asked what they have tried (10 hours ago). OP provides satisfactory response (10 hours ago). This means, roughly, that within the hour the OP was showing a willingness to engage. And yet the question is closed! It does not make MSE seem friendly...(looking at the edits - moderator intervention? Seriously?!?) – user1729 May 5 '13 at 13:49
• My point is, the default does seem to be "close". Even if this isn't the majority default, the fact is that it happens enough for new users (for example, Tristen, the OP here) to notice means we have a problem. – user1729 May 5 '13 at 13:51
• @user1729 Tristen's observations apparently come "from the comments to most of the posts I have seen over the last couple of days on meta". The second comment under the question also states that. Sure, reading meta debates is not something I would recommend to new users. (Eric Naslund said something of the sort in his resignation post). – 75064 May 5 '13 at 14:31
• @user75064 Ah, forgot about that part of his post. However, as I said in my comment to the question, whenever I suggest to my students that they ask questions here they do not want to. – user1729 May 5 '13 at 14:34
• @user1729 I wonder if your students' reluctance has to do with Math.se specifically or online fora in general. Are they comfortable with asking at Yahoo Answers or Art of Problem Solving? – 75064 May 5 '13 at 14:36
• @user75064 Just MSE. (And it isn't just a small subset of a single year group, and nor are they studying basic calculus.) – user1729 May 5 '13 at 14:53
• @JyrkiLahtonen Like editing Wikipedia, contributing to an SE site is a social activity. But SE is certainly not designed with social networking in mind; there is no way to send a message to another user, for example. So, if the OP finds the site not very social, it may be by design "This site is all about getting answers. It's not a discussion forum. There's no chit-chat." Of course I do not advocate going from "not very social" to "anti-social". – 75064 May 5 '13 at 14:59
• I think sometimes there is quite a bit of chit-chat going on. I don't usually visit our chatroom (which is designed for that) because my time zone is what it is. But in the comments many jokes and anecdotes are shared, mutual cheering for each other takes place, professional courtesies are exchanged and such. Some would like the site to be all business, but we also like to add some levity given half a chance. Granted, the platform is not ideal for that, but it is good enough. – Jyrki Lahtonen May 5 '13 at 16:15
• But conceding the point about the difference between social activity and social networking. – Jyrki Lahtonen May 14 '13 at 19:49

Keep it short, this question Vector field on an odd sphere by this user https://math.stackexchange.com/users/52042/b11

He "pinged" me six times to answer his question. I had already given everything necessary in my first comment. After I said I had done enough, he serially downvoted me and Zev. This person sees MSE as an alternative to ever reading his book or working.

I think Asaf would know how to make up a list of probable students asking way too many questions.

The worry here seems to be about new users. Fine. With no visible track record, it would help to know the book and what material is in the chapter immediately preceding the question asked. This would tell me that the person asking has actually read the material immediately preceding the question.

Here is another winner, https://math.stackexchange.com/users/12796/victor Little interaction with me, I got weary early.

• I sympathize: repeated pings of this kind are extremely obnoxious, apart from any integrity issues. There should be a way to walk away from a thread and never hear from it again. Hypothetically speaking: if you deleted your comment under the question, would the OP be able to ping you again? I could not find an answer in meta.SO thread on @replies. I know it's impossible to ping a user who never participated in the thread; I don't know what happens if the user participated but then removed their input from the thread. – 75064 May 5 '13 at 18:24
• @user75064, I left it there. I won't say the pings failed to piss me off, but I did not have much trouble deciding what to do, which was to say that I had done enough. Years ago, I would regularly get caught giving some answer, then the OP (on MO or here) would say You haven't done enough, write more, and I would. Lately, not as much. – Will Jagy May 5 '13 at 18:45
• I’m afraid that my reaction is So what? There are obnoxious people everywhere, and B11 is most unrepresentative of my experience. And I’ve little sympathy with complaints about Victor: he accepts answers, and he’s answered $13$ questions himself, with six acceptances. – Brian M. Scott May 5 '13 at 18:48
• Asaf doesn't know SQL (and has very little motivation to learn that too), so he is limited to the available data.SE queries, with the occasional minor modification. – Asaf Karagila May 5 '13 at 18:48
• @Brian, I was aware that you and I disagree on most MSE issues, certainly after your comments on Qiaochu's verbatim homework Meta proposals. I don't expect to convince many people of my viewpoint, but I do like to say it now and then. You hold the majority view, including the continuing moderators. Want to be moderator? It would involve less friction for you than for many others. – Will Jagy May 5 '13 at 19:01
• I have had a lot of multiple-ping experiences (these are called help vampires on MSO) but this has been more the case with the eager, show-maximum-effort posters who are being held up as the model of good question etiquette. I am coming more and more to two ideas from experience on the site: -- not answering questions where there is any ambiguity about what is a complete answer --- and viewing "shown work" as a negative unless the OP wants the work analyzed (so if somebody does post their efforts, it is as logical as WHYT to ask, "do you want that examined or is it decoration?"). – zyx May 5 '13 at 19:24
• @zyx, what is MSO? oh, and what is WHYT, perhaps what have you tried? I don't see any zyx on MO, do you use a different name? – Will Jagy May 5 '13 at 19:38
• Meta Stack Overflow ( meta.stackoverflow.com/search?q=vampires ) and, yes, What Have You Tried. – zyx May 5 '13 at 19:42
• Will, I am a frequent MO user but under a different name. Maybe the two profiles will get combined when MO changes to SE 2.0, maybe not. Since these sites are different religions, in some sense, I separate the identities. – zyx May 5 '13 at 19:53
• I think we can save ourselves a lot of heartburn by simply recognizing why we are here on M.SE: because we enjoy math and people who enjoy math. I answer certain questions here because I love to solve the problems posed in those questions, and I love to interact with others on this site. As soon as it is no longer fun, I am done. I do not have a set limit, but when someone makes it clear that they are here because they do not like math, I will note their name and disappear. – Ron Gordon May 5 '13 at 19:53
• Now, that same user has starting pinging people in other completely unrelated questions for help: math.stackexchange.com/a/382465/19440 – mrf May 5 '13 at 20:21
• @mrf, there is also a Chat feature for MSE. This has, probably against system design, remained a single room where people drop in and later drop out. There are plenty of newcomers who put a question on Main and then bug people on Chat about it forever. – Will Jagy May 5 '13 at 20:48
• @Ron: I sympathize, but I don’t myself actually mind helping those who don’t like mathematics if they’re willing to work at it. Some folks may remember a beginning calculus student whose name began with J who complained bitterly (and somewhat unreasonably) about the unreasonable expectations of his instructor and the author of his textbook but who posted a lot of questions and did actually persevere, if not always to very good effect; I can work with someone like that, though I could have done with less moaning. – Brian M. Scott May 6 '13 at 3:44
• @user1729, "They all hated maths, all claimed they were rubbish at it, and they are all going on to be maths teachers" - I now wonder how many "teachers" past and present were actually that way. *shudders* If you did manage to get through 'em, then good on you! – J. M. is a poor mathematician May 6 '13 at 10:46
• @BrianM.Scott: I think we are on the same page. I was complaining about the posters who do not want to work, but just want everything done for them. I totally enjoy working with people who are having a rough time grasping this or that concept, but are clearly giving it a go. – Ron Gordon May 8 '13 at 23:32

I am sorry that you have not been feeling welcome here. I hope that this feeling will go away when you see how much "good" is actually going on here. And I hope that we might convince you that your feelings are mostly a misunderstanding.

You write:

...from the comments to most of the posts I have seen over the last couple of days on meta, nobody really wants to see anything from anyone new on MSE

Remember that we are all people here and we make mistakes. Some times our mistake is that we speak/write before we think. However, I don't see how comments given recently could give you the impression that we don't want to see anything from anyone new.

So let me be somebody who is now telling you that I want to see something from, in particular, new people.

There seems to be alot of bitterness, especially regarding the homework problems situation.

That is true, and again, the words spoken aren't always the best. As mentioned, we don't have anything against "new people", but it can be a bit frustrating when you see a question that just commands "do my homework". For me personally, there is an ethical problem here. As a teacher, I take cheating very serious, and I wouldn't not want my students seeking out someone else to actually do there homework. It is fine helping people with homework questions. In my opinion a student doesn't learn much from just being given a solution. Learning happens when the student has to think for him/herself. And it is hard for me to be a part of something if I have a feeling that it is ethical. If the word on the street is that "Over on Math.SE they just give the answer away, and I don't have to do anything. It is great, I don't even have to do my own homework anymore", then do I really want my name associated with that?

While I understand that many people may be looking for a handout it is unfair to assume that is the case for anybody asking a homework question, or help understanding or clarifying some aspect of a particular area. Some people do make an effort, just saying.

Yes! Lots of people do make an effort. I see plenty of good homework questions and I see a lot of good answers. No one (that I know of) is saying that all homework questions are bad in and of themselves. The problem is the question that shows absolutely no effort.

If I am to try and help you, then the best thing you can do is to tell me what the issue is. If you have a (homework) problem that you can't do, then tell me what it is about the problem that is causing trouble. If you have absolutely no thoughts about the problem, you could tell me what class the problem is from. Where did you come across the problem, and so on. Those questions, I would say, you should always be able to answer. And writing just a bit about where the problem comes from and a bit about your background ... well that is effort in my mind. I don't know your background. If you have never heard about the product rule, then it might not be that helpful for me just to show how you solve the problem using the product rule. I might want to tell you about the product rule.

Oh, and no offence taken :)

• It has been a great pleasure to see how this discussion has played out. – Tristen May 5 '13 at 22:19

Instead of "What have you tried?" perhaps we should write "If you show us what you have tried perhaps we can figure out how that can be the start of a solution." Oral statements have an associated tone of speech. Written statements lose the tone. A statement of some sort needs to indicate the tone.

• The words "quality standards" have a similar effect. To see how current practices are working, the daily closed list has examples like this ( math.stackexchange.com/questions/391115/convergence-tests ) and this ( math.stackexchange.com/questions/385739/graduate-linear ) . There is un-necessary antagonism and drama that can be avoided by silent methods like downvote, close vote, do nothing (and let others decide if they want to answer), add filterable tag. – zyx May 14 '13 at 19:13
• @zyx I do not see how a downvote is helpful in such situations. – user1729 May 16 '13 at 10:10


text:
class PStatThread

A lightweight class that represents a single thread of execution to PStats. It corresponds one-to-one with Panda’s Thread instance.

Inheritance diagram

PStatThread(PStatClient *client, int index)
PStatThread(Thread *thread, PStatClient *client = nullptr)
PStatThread(PStatThread const &copy)

Normally, this constructor is called only from PStatClient. Use one of the constructors below to create your own Thread.

Normally, this constructor is called only from PStatClient. Use one of the constructors below to create your own Thread.

void add_frame(PStatFrameData const &frame_data)

This is a slightly lower-level version of new_frame() that also specifies the data to send for this frame.

int get_index(void) const

Returns the index number of this particular thread within the PStatClient.

Thread *get_thread(void) const

Returns the Panda Thread object associated with this particular PStatThread.

void new_frame(void)

This must be called at the start of every “frame”, whatever a frame may be deemed to be, to accumulate all the stats that have collected so far for the thread and ship them off to the server.

Calling PStatClient::thread_tick() will automatically call this for any threads with the indicated sync name.