I have some events (an array of groups of events) and I want to map those events to segments using a logarithmic scale.
There are some rules I want the solution to obey to:
Math.log(x+1) must be used as it scales well 1 and numbers smaller than 1
I want to calculate the single segments and not only the total
The sum of the segments of a group i must be equal to the sum of the segments of another group j if the linear sums of the events are equal (i.e. if I have the events [1, 1] and [2] the total of the mapped segments of the two groups must be equal)
I have developed the solution you see below but it works partially, as the sum of groups[0].segments is different from the sum of groups[1].segments, because log(1+1)+log(1+1) != log(2+1)
How can I use Math.log(x+1) to scale the events while having rule 3 working?
var logSegmentLen = function(x) {
return Math.log(x+1);
}
var groupOfSegmentsTotal = function(segmentLenFn) {
var f = function(arrayOfSegments) {
let segments = arrayOfSegments.map(segmentLenFn);
let total = segments.reduce((a,b) => a+b,0);
return {
total: total,
segments: segments
}
}
return f;
}
var events = [ [1, 1], [2]]
var groups = events.map(groupOfSegmentsTotal(logSegmentLen));
console.log(groups[0].segments, groups[1].segments);
console.log(Math.abs(groups[0].total - groups[1].total) < 0.001); // true must be printed
How can I use Math.log(x+1) to scale the events while having rule 3 working?
Apparently this is just impossible. Your requirement #3 which can be restated as for given scale function F(x)
sum(Xi) = sum(Yj) => sum(F(Xi)) = sum(F(Yj))
actually implies that the only F(x)
that fits it is of form F(x) = k*x
i.e. just a linear scale. Any non-linear scale (including logarithmic) will break that requirement. You probably should describe your higher-level problem and somebody might be able to come up with non-self-contradicting translation of that problem.
Sidenote Sketch of the proof. Fix {Xi} to be just a collection of n
identical values x
and {Yj} to be a collection of m
identical y
. So
sum(Xi) = n*x
sum(Yj) = m*y
sum(F(Xi)) = n*F(x)
sum(F(Yj)) = m*F(y)
and the requirement becomes:
sum(Xi) = sum(Yj) => sum(F(Xi)) = sum(F(Yj))
n*x = m*y => n*F(x) = m*F(y)
And this holds for arbitrary integers n
and m
. Now lets fix F(1)
= k
. It means that for any m/n
F(m/n) = m/n*k
. As real numbers can be approximated by fractions with arbitrary precision, it means that for any x
F(x) = x*k
.