<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Auto-Sizing Columns</title>
	<atom:link href="http://blog.jasondonenfeld.com/35/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.jasondonenfeld.com/35</link>
	<description>{{{ ZX2C4 }}}</description>
	<lastBuildDate>Fri, 30 Jul 2010 14:21:26 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
	<item>
		<title>By: Andreas</title>
		<link>http://blog.jasondonenfeld.com/35#comment-80</link>
		<dc:creator>Andreas</dc:creator>
		<pubDate>Sun, 30 Nov 2008 09:48:53 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-80</guid>
		<description>@Jason:

I wasn&#039;t able to find a combination of widths, which results in any suggested ratio becoming greater than R (or MAX)... the problem with my algorithm is a bad behavior with very few columns (i.e. tables with 1 column..)</description>
		<content:encoded><![CDATA[<p>@Jason:</p>
<p>I wasn&#8217;t able to find a combination of widths, which results in any suggested ratio becoming greater than R (or MAX)&#8230; the problem with my algorithm is a bad behavior with very few columns (i.e. tables with 1 column..)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tomas P.</title>
		<link>http://blog.jasondonenfeld.com/35#comment-78</link>
		<dc:creator>Tomas P.</dc:creator>
		<pubDate>Sun, 30 Nov 2008 03:53:46 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-78</guid>
		<description>Yes, for large n, sorting first would be better, but to do that (efficiently) pretty much needs what I call a more complicated datastructure. If you can accept the increase of the code size enabling you to use sorting, that uhuu&#039;s code is the way to go.

Sorting according to the ratios CH[i]/M[i] (ratios of hints to maxima) from largest to smallest would be needed for this to work in the case maximum sizes M[i] are set differently for each column.

There usually aren&#039;t &quot;formulas&quot; (formulas that would be helpful for any programming) that would do what a (pretty much) one-line loop of uhuu does!</description>
		<content:encoded><![CDATA[<p>Yes, for large n, sorting first would be better, but to do that (efficiently) pretty much needs what I call a more complicated datastructure. If you can accept the increase of the code size enabling you to use sorting, that uhuu&#8217;s code is the way to go.</p>
<p>Sorting according to the ratios CH[i]/M[i] (ratios of hints to maxima) from largest to smallest would be needed for this to work in the case maximum sizes M[i] are set differently for each column.</p>
<p>There usually aren&#8217;t &#8220;formulas&#8221; (formulas that would be helpful for any programming) that would do what a (pretty much) one-line loop of uhuu does!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jason Donenfeld</title>
		<link>http://blog.jasondonenfeld.com/35#comment-76</link>
		<dc:creator>Jason Donenfeld</dc:creator>
		<pubDate>Sun, 30 Nov 2008 00:54:40 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-76</guid>
		<description>@uhuu
By iterative, I just mean running the loop an unknown amount of times until all the conditions are met. But I didn&#039;t read your first post carefully enough; the O(n&lt;sup&gt;2&lt;/sup&gt;) algorithm, which is basically the same as the one discussed in the blog post, will in fact have the redistribution loop run a maximum of n times, since a maximum of n columns can be set to R. Good thinking. I guess that redefines my problem slightly, to read &quot;can anybody beat this efficiency&quot;, which I &lt;i&gt;think&lt;/i&gt; you might have done with your sorting O(n log n) solution, which is genius. I still need to think your solution through carefully.

What I would really like to know, however, is if anyone can come up with a simple expression for O&lt;sub&gt;i&lt;/sub&gt; that only uses the 4 basic operations, and maybe the min function.

Good work though, uhuu, I think your sorting-based algorithm is the most efficient one yet.</description>
		<content:encoded><![CDATA[<p>@uhuu<br />
By iterative, I just mean running the loop an unknown amount of times until all the conditions are met. But I didn&#8217;t read your first post carefully enough; the O(n<sup>2</sup>) algorithm, which is basically the same as the one discussed in the blog post, will in fact have the redistribution loop run a maximum of n times, since a maximum of n columns can be set to R. Good thinking. I guess that redefines my problem slightly, to read &#8220;can anybody beat this efficiency&#8221;, which I <i>think</i> you might have done with your sorting O(n log n) solution, which is genius. I still need to think your solution through carefully.</p>
<p>What I would really like to know, however, is if anyone can come up with a simple expression for O<sub>i</sub> that only uses the 4 basic operations, and maybe the min function.</p>
<p>Good work though, uhuu, I think your sorting-based algorithm is the most efficient one yet.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: uhuu</title>
		<link>http://blog.jasondonenfeld.com/35#comment-75</link>
		<dc:creator>uhuu</dc:creator>
		<pubDate>Sun, 30 Nov 2008 00:33:44 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-75</guid>
		<description>Sorry, but what do you mean by iterative algorithm? Every for loop is iterative? Usually the word iterative refers to the fact that after every iteration you get little bit closer and the stopping time of the method depends on the acceptable error you set.

In that use of the iterative neither of the methods I mentioned earlier are iterative (the stopping time does not depend on the error level, given an input the number of steps is finite, regardless of error). The second approach O(n log n) I mentioned does just one loop over the widths after sorting, assigning each column its optimal value.

basically it is like this:
// M - requested widths
// O - optimal widths
// R - maximum allowed width
// tableWidth

// do sorting
// assuming that M and O are now in the order or descending values of M:
remainingWidth = tableWidth;
remainingRequested = sum(M);
// doing loop starting from the largest:
for (i=0; i&lt;n; i++) {
  O[i] = min( R*tableWidth, remainingWidth * M[i]/remainingRequested);
  remainingWidth -= O[i];
  remainingRequested -= M[i];
}

When you implement this just replace i with sortedM[i] inside the loop, where sortedM contains the indexes of M when it would be sorted, so you do not have to reorder the original arrays M and O in the sorting stage.</description>
		<content:encoded><![CDATA[<p>Sorry, but what do you mean by iterative algorithm? Every for loop is iterative? Usually the word iterative refers to the fact that after every iteration you get little bit closer and the stopping time of the method depends on the acceptable error you set.</p>
<p>In that use of the iterative neither of the methods I mentioned earlier are iterative (the stopping time does not depend on the error level, given an input the number of steps is finite, regardless of error). The second approach O(n log n) I mentioned does just one loop over the widths after sorting, assigning each column its optimal value.</p>
<p>basically it is like this:<br />
// M &#8211; requested widths<br />
// O &#8211; optimal widths<br />
// R &#8211; maximum allowed width<br />
// tableWidth</p>
<p>// do sorting<br />
// assuming that M and O are now in the order or descending values of M:<br />
remainingWidth = tableWidth;<br />
remainingRequested = sum(M);<br />
// doing loop starting from the largest:<br />
for (i=0; i&lt;n; i++) {<br />
  O[i] = min( R*tableWidth, remainingWidth * M[i]/remainingRequested);<br />
  remainingWidth -= O[i];<br />
  remainingRequested -= M[i];<br />
}</p>
<p>When you implement this just replace i with sortedM[i] inside the loop, where sortedM contains the indexes of M when it would be sorted, so you do not have to reorder the original arrays M and O in the sorting stage.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jason Donenfeld</title>
		<link>http://blog.jasondonenfeld.com/35#comment-74</link>
		<dc:creator>Jason Donenfeld</dc:creator>
		<pubDate>Sat, 29 Nov 2008 22:11:26 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-74</guid>
		<description>@Andreas
One question: After &quot;requestedWidths[i] += requestedWidths[i]*available/distributeTo;&quot;, is requestedWidths[i] guaranteed to be less than or equal to R? Or does it suffer from the same problem as the others?</description>
		<content:encoded><![CDATA[<p>@Andreas<br />
One question: After &#8220;requestedWidths[i] += requestedWidths[i]*available/distributeTo;&#8221;, is requestedWidths[i] guaranteed to be less than or equal to R? Or does it suffer from the same problem as the others?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Andreas</title>
		<link>http://blog.jasondonenfeld.com/35#comment-73</link>
		<dc:creator>Andreas</dc:creator>
		<pubDate>Sat, 29 Nov 2008 20:34:27 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-73</guid>
		<description>hrmpf..... (too aggressive &quot;untagging&quot; ;-) )
http://users.informatik.haw-hamburg.de/~krohn_d/temp/columnSizing.txt</description>
		<content:encoded><![CDATA[<p>hrmpf&#8230;.. (too aggressive &#8220;untagging&#8221; <img src='http://blog.jasondonenfeld.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  )<br />
<a href="http://users.informatik.haw-hamburg.de/~krohn_d/temp/columnSizing.txt" rel="nofollow">http://users.informatik.haw-hamburg.de/~krohn_d/temp/columnSizing.txt</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Andreas</title>
		<link>http://blog.jasondonenfeld.com/35#comment-71</link>
		<dc:creator>Andreas</dc:creator>
		<pubDate>Sat, 29 Nov 2008 20:23:45 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-71</guid>
		<description>my version needs &lt;=4 loops... that&#039;s not O(1) but at least not running an undefinable anmount of times..
double[] requestedWidths = new double[columnCount];
double totalRequested = 0;
for(int i = 0; i &lt; columnCount; i++){
	requestedWidths[i] = sizeHintForColumn(i);
	totalRequested += requestedWidths[i];
}
double MAX = 0.4;
double available = 0;
double distributeTo = 0;
for(int i = 0; i &lt; columnCount; i++){
	requestedWidths[i] /= totalRequested;
	if(requestedWidths[i] &gt; MAX){
		available += requestedWidths[i] - MAX;
		requestedWidths[i] = MAX;
	}
	else{
		distributeTo += requestedWidths[i];
	}
}
if(available&gt;0&amp;&amp;distributeTo&gt;0){
	for(int i = 0; i &lt; columnCount; i++){
		if(requestedWidths[i]&lt;MAX)
			requestedWidths[i] += requestedWidths[i]*available/distributeTo;
	}
}
for(int i = 0; i &lt; columnCount; i++){
	m_suggestedRatio[i] = requestedWidths[i];
}

..there may be room for improvement but in my little (C#.. yes, I know) Application it works..</description>
		<content:encoded><![CDATA[<p>my version needs &lt;=4 loops&#8230; that&#8217;s not O(1) but at least not running an undefinable anmount of times..<br />
double[] requestedWidths = new double[columnCount];<br />
double totalRequested = 0;<br />
for(int i = 0; i < columnCount; i++){<br />
	requestedWidths[i] = sizeHintForColumn(i);<br />
	totalRequested += requestedWidths[i];<br />
}<br />
double MAX = 0.4;<br />
double available = 0;<br />
double distributeTo = 0;<br />
for(int i = 0; i < columnCount; i++){<br />
	requestedWidths[i] /= totalRequested;<br />
	if(requestedWidths[i] > MAX){<br />
		available += requestedWidths[i] &#8211; MAX;<br />
		requestedWidths[i] = MAX;<br />
	}<br />
	else{<br />
		distributeTo += requestedWidths[i];<br />
	}<br />
}<br />
if(available>0&#038;&#038;distributeTo>0){<br />
	for(int i = 0; i < columnCount; i++){<br />
		if(requestedWidths[i]<MAX)<br />
			requestedWidths[i] += requestedWidths[i]*available/distributeTo;<br />
	}<br />
}<br />
for(int i = 0; i < columnCount; i++){<br />
	m_suggestedRatio[i] = requestedWidths[i];<br />
}</p>
<p>..there may be room for improvement but in my little (C#.. yes, I know) Application it works..</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jason Donenfeld</title>
		<link>http://blog.jasondonenfeld.com/35#comment-70</link>
		<dc:creator>Jason Donenfeld</dc:creator>
		<pubDate>Sat, 29 Nov 2008 20:06:54 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-70</guid>
		<description>@BennyM @Kevin
Your approaches have demonstrated the problem in a much more striking way: As pointed out by Kevin, the trouble is extending the hypercube too far in a different dimension during the redistribution. We can look at it in N-dimensions, but the burden of the R restriction still requires some clever trick.

@Tomas P
This is elegant, but as you said, it is still iterative. That&#039;s also interesting about having a minimum instead of a maximum. Essentially they&#039;re the same, but thinking about it as a minimum may be more effective.

@uhuu
Both algorithms you&#039;ve mentioned are iterative as soon as you say &quot;repeat this, as long as...&quot;, and I basically implement them already in the post, except for the part about sorting.

@r0b0t
That looks like the start of a clever solution... One question/potential problem: after distributing the excess in the third iteration, if R[i] &gt; R, the excess in that case only get distributed to the remaining i+1 to N columns. Is this desired? What if there was an i-x column earlier that was far below R? ...or maybe this nuance is actually the essence of the solution?</description>
		<content:encoded><![CDATA[<p>@BennyM @Kevin<br />
Your approaches have demonstrated the problem in a much more striking way: As pointed out by Kevin, the trouble is extending the hypercube too far in a different dimension during the redistribution. We can look at it in N-dimensions, but the burden of the R restriction still requires some clever trick.</p>
<p>@Tomas P<br />
This is elegant, but as you said, it is still iterative. That&#8217;s also interesting about having a minimum instead of a maximum. Essentially they&#8217;re the same, but thinking about it as a minimum may be more effective.</p>
<p>@uhuu<br />
Both algorithms you&#8217;ve mentioned are iterative as soon as you say &#8220;repeat this, as long as&#8230;&#8221;, and I basically implement them already in the post, except for the part about sorting.</p>
<p>@r0b0t<br />
That looks like the start of a clever solution&#8230; One question/potential problem: after distributing the excess in the third iteration, if R[i] > R, the excess in that case only get distributed to the remaining i+1 to N columns. Is this desired? What if there was an i-x column earlier that was far below R? &#8230;or maybe this nuance is actually the essence of the solution?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: r0b0t</title>
		<link>http://blog.jasondonenfeld.com/35#comment-69</link>
		<dc:creator>r0b0t</dc:creator>
		<pubDate>Sat, 29 Nov 2008 15:29:42 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-69</guid>
		<description>The third iteration is of course wrong. It should be:

do 
Z=1-(R[1]+…+R[n]) 
for i=1..n do {if mem[i]==1 then R[i]=R[i]+M[i]/(M[1]*mem[1]+..+M[n]*mem[n])*Z;
if R[i]&gt;R then R[i]=R; mem[i]=0}
until Z ==0

This task has it&#039;s complexity bounded below by O(n^2) because calculating the value of R[i] has impact on all the so far uncomputed values R[j].</description>
		<content:encoded><![CDATA[<p>The third iteration is of course wrong. It should be:</p>
<p>do<br />
Z=1-(R[1]+…+R[n])<br />
for i=1..n do {if mem[i]==1 then R[i]=R[i]+M[i]/(M[1]*mem[1]+..+M[n]*mem[n])*Z;<br />
if R[i]&gt;R then R[i]=R; mem[i]=0}<br />
until Z ==0</p>
<p>This task has it&#8217;s complexity bounded below by O(n^2) because calculating the value of R[i] has impact on all the so far uncomputed values R[j].</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: r0b0t</title>
		<link>http://blog.jasondonenfeld.com/35#comment-68</link>
		<dc:creator>r0b0t</dc:creator>
		<pubDate>Sat, 29 Nov 2008 15:12:58 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-68</guid>
		<description>Initialize ratios for O[i] as follows
for i=1..n do {R[i]=M[i]/(M[1]+..+M[n]);mem[i]=1}

Then apply the restriction while remembering on which columns: 
for i=1..n do {if R &lt; R[i] then R[i]=R; mem[i]=0}

Finally distribute the remaining ratio Z=1-(R[1]+...+R[n]) via
for i=1..n do {if mem[i]==1 then R[i]=R[i]+M[i]/(M[1]*mem[1]+..+M[n]*mem[n])*Z}

Maybe this can be done without iteration by I think the result would be rather obfuscated. Take for example the Cramer&#039;s rule - in it&#039;s general form for NxN matrices it requires the determinant function.</description>
		<content:encoded><![CDATA[<p>Initialize ratios for O[i] as follows<br />
for i=1..n do {R[i]=M[i]/(M[1]+..+M[n]);mem[i]=1}</p>
<p>Then apply the restriction while remembering on which columns:<br />
for i=1..n do {if R &lt; R[i] then R[i]=R; mem[i]=0}</p>
<p>Finally distribute the remaining ratio Z=1-(R[1]+&#8230;+R[n]) via<br />
for i=1..n do {if mem[i]==1 then R[i]=R[i]+M[i]/(M[1]*mem[1]+..+M[n]*mem[n])*Z}</p>
<p>Maybe this can be done without iteration by I think the result would be rather obfuscated. Take for example the Cramer&#8217;s rule &#8211; in it&#8217;s general form for NxN matrices it requires the determinant function.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: uhuu</title>
		<link>http://blog.jasondonenfeld.com/35#comment-67</link>
		<dc:creator>uhuu</dc:creator>
		<pubDate>Sat, 29 Nov 2008 13:15:33 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-67</guid>
		<description>Maybe I&#039;m missing something, but a quite straight-forward non-iterative algorithms can solve this. I&#039;ve thought of two solutions, one is worst case O(n^2) and the other O(n log n).

For worst case speed of O(n^2) you calculate all widths without the additional R constraint. Then do a loop over all widths and cut all values exceeding the maximum R and calculate the sum of the cut widths. And distribute that sum of excess widths proportionally over all columns that are not equal to maximum R (or not greater than R, but of course none of them can be above R in this case). And repeat this, as long as no excess was cut. In the worst case you do that loop n times. Not more than n times, since every time either your loop stops (no excess was cut) or at least one of the widths that was not R becomes R and will stay R till the end of the iteration.

For O(n log n) you need to sort the widths according to their size. This takes O(n log n), after that the remaining part requires just O( n ). So after sorting you start from the largest width. You calculate whether it exceeds the limit R and cut it if necessary and set that to be its optimal value O (and that is also the final optimal value for that column). After that you go to a subproblem of finding the widths of the remaining n-1 columns by reducing the remaining table width by the optimal width value you found for the largest column.

Sorry I was lazy not to write some (pseudo)code... if these explanations were too ambiguous let me know, I put down some code :), given that I understood your problem correctly.</description>
		<content:encoded><![CDATA[<p>Maybe I&#8217;m missing something, but a quite straight-forward non-iterative algorithms can solve this. I&#8217;ve thought of two solutions, one is worst case O(n^2) and the other O(n log n).</p>
<p>For worst case speed of O(n^2) you calculate all widths without the additional R constraint. Then do a loop over all widths and cut all values exceeding the maximum R and calculate the sum of the cut widths. And distribute that sum of excess widths proportionally over all columns that are not equal to maximum R (or not greater than R, but of course none of them can be above R in this case). And repeat this, as long as no excess was cut. In the worst case you do that loop n times. Not more than n times, since every time either your loop stops (no excess was cut) or at least one of the widths that was not R becomes R and will stay R till the end of the iteration.</p>
<p>For O(n log n) you need to sort the widths according to their size. This takes O(n log n), after that the remaining part requires just O( n ). So after sorting you start from the largest width. You calculate whether it exceeds the limit R and cut it if necessary and set that to be its optimal value O (and that is also the final optimal value for that column). After that you go to a subproblem of finding the widths of the remaining n-1 columns by reducing the remaining table width by the optimal width value you found for the largest column.</p>
<p>Sorry I was lazy not to write some (pseudo)code&#8230; if these explanations were too ambiguous let me know, I put down some code <img src='http://blog.jasondonenfeld.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> , given that I understood your problem correctly.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Yves</title>
		<link>http://blog.jasondonenfeld.com/35#comment-66</link>
		<dc:creator>Yves</dc:creator>
		<pubDate>Sat, 29 Nov 2008 12:27:48 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-66</guid>
		<description>From your chat it just looks like you need to solve a system of 3 simultaneous equations - which is easy- am I missing something here?</description>
		<content:encoded><![CDATA[<p>From your chat it just looks like you need to solve a system of 3 simultaneous equations &#8211; which is easy- am I missing something here?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tomas P.</title>
		<link>http://blog.jasondonenfeld.com/35#comment-64</link>
		<dc:creator>Tomas P.</dc:creator>
		<pubDate>Sat, 29 Nov 2008 08:56:22 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-64</guid>
		<description>I have no idea what happened with the for() loop in my first posting. The second try:

//Calculate the widths of all non-maxed-out columns
for{i=1;i&lt;=n;i++)
  if (A[i] != M[i]) 
    {A[i]=round(CH[i]*W/T), W-=A[i], T-=CH[i];}</description>
		<content:encoded><![CDATA[<p>I have no idea what happened with the for() loop in my first posting. The second try:</p>
<p>//Calculate the widths of all non-maxed-out columns<br />
for{i=1;i&lt;=n;i++)<br />
  if (A[i] != M[i])<br />
    {A[i]=round(CH[i]*W/T), W-=A[i], T-=CH[i];}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tomas P.</title>
		<link>http://blog.jasondonenfeld.com/35#comment-63</link>
		<dc:creator>Tomas P.</dc:creator>
		<pubDate>Sat, 29 Nov 2008 08:53:48 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-63</guid>
		<description>While I do not quite understand why is it useful to require the &quot;maximum&quot; condition (I could imagine why someone might want a &quot;minimum&quot; condition) , the default column sizing is often very poor, it would be definitely nice if more people tried to come up with some sensible starting values.

For the kind of solution you want, the `iteration&#039; probably cannot be avoided (al least without the use of some complex data structures) , but something along the lines of the following (pseudo)code seems simpler and more general: all used variables are integers, the only (brief) use of floats is in the last for{} loop.
Sorry for changing your notation... your M corresponds to my CH, your O to my A. I did not change the indexes, though, so that the arrays run from 1 to n, which may not be ideal...
 
The same units (say, pixels) are used for A[], M[], W.
Some possibly other units can be used for CH[], T (these are used purely for dealing with proportions).

The following ought to work with a certain maximum set individually for each column. Replacing M[i]&#039;s with a single maximum M is possible, of course.


INPUT
Constants: n number of columns,
           M[1..n] maximum allowed column widths, CH[1..n] column width hints
Variables: W total (remaining) width

OUTPUT
           A[1..n] final column widths

LOCAL VARIABLES
Variables: i index in 1..n,
           W total remaining width, T total hints of not-maxed-out-yet column

Invariants: W/T nondecreasing in the while{} loop,
           number of maxed-out columns increasing

//Initialize ... {i=1, T = sum over 1..n of CH[i], A=[0,..,0]}
...
//Find all maxed-out columns, give them the M[i] width
while(i= T*M[i]) 
    {A[i]=M[i], W-=M[i], T-=CH[i]; i=0}
    //i=0 means start over, since we found a new maxed-out column
    //and hence W/T might have increased
  i++;
}
//Calculate the widths of all non-maxed-out columns
for{i=1,i0) ... //Fail (cannot fill W when restricted by such small maxima M[])
else ...  //Return A[1..n]


Use while(++i&lt;=n) if you really really want to make the whole while statement a one-liner (initializing with i=0).

That does not change the fact that the body of while() may execute n^2 times, but this is hardly an issue for the intended application.

The body of the last loop bothers with updating W and T so that the rounding/discretizations errors (which are spread over A[])  average to zero (I hope, the sum of A[] should be the originally input W).</description>
		<content:encoded><![CDATA[<p>While I do not quite understand why is it useful to require the &#8220;maximum&#8221; condition (I could imagine why someone might want a &#8220;minimum&#8221; condition) , the default column sizing is often very poor, it would be definitely nice if more people tried to come up with some sensible starting values.</p>
<p>For the kind of solution you want, the `iteration&#8217; probably cannot be avoided (al least without the use of some complex data structures) , but something along the lines of the following (pseudo)code seems simpler and more general: all used variables are integers, the only (brief) use of floats is in the last for{} loop.<br />
Sorry for changing your notation&#8230; your M corresponds to my CH, your O to my A. I did not change the indexes, though, so that the arrays run from 1 to n, which may not be ideal&#8230;</p>
<p>The same units (say, pixels) are used for A[], M[], W.<br />
Some possibly other units can be used for CH[], T (these are used purely for dealing with proportions).</p>
<p>The following ought to work with a certain maximum set individually for each column. Replacing M[i]&#8216;s with a single maximum M is possible, of course.</p>
<p>INPUT<br />
Constants: n number of columns,<br />
           M[1..n] maximum allowed column widths, CH[1..n] column width hints<br />
Variables: W total (remaining) width</p>
<p>OUTPUT<br />
           A[1..n] final column widths</p>
<p>LOCAL VARIABLES<br />
Variables: i index in 1..n,<br />
           W total remaining width, T total hints of not-maxed-out-yet column</p>
<p>Invariants: W/T nondecreasing in the while{} loop,<br />
           number of maxed-out columns increasing</p>
<p>//Initialize &#8230; {i=1, T = sum over 1..n of CH[i], A=[0,..,0]}<br />
&#8230;<br />
//Find all maxed-out columns, give them the M[i] width<br />
while(i= T*M[i])<br />
    {A[i]=M[i], W-=M[i], T-=CH[i]; i=0}<br />
    //i=0 means start over, since we found a new maxed-out column<br />
    //and hence W/T might have increased<br />
  i++;<br />
}<br />
//Calculate the widths of all non-maxed-out columns<br />
for{i=1,i0) &#8230; //Fail (cannot fill W when restricted by such small maxima M[])<br />
else &#8230;  //Return A[1..n]</p>
<p>Use while(++i&lt;=n) if you really really want to make the whole while statement a one-liner (initializing with i=0).</p>
<p>That does not change the fact that the body of while() may execute n^2 times, but this is hardly an issue for the intended application.</p>
<p>The body of the last loop bothers with updating W and T so that the rounding/discretizations errors (which are spread over A[])  average to zero (I hope, the sum of A[] should be the originally input W).</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Kevin Kofler</title>
		<link>http://blog.jasondonenfeld.com/35#comment-62</link>
		<dc:creator>Kevin Kofler</dc:creator>
		<pubDate>Sat, 29 Nov 2008 06:45:32 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-62</guid>
		<description>@BennyM: Projecting along the normal is the wrong thing to do here. The normal vector of that hypersurface is simply a vector of all ones. Projecting along it means removing the same k from all Oi, it&#039;s not a proportional resize. What you actually want is the projection along the line (0,M) where 0 is the origin (vector of all zeros) and M is the vector of Mi, i.e. the intersection of that line with the hyperplane. Computing that is trivial (just multiply all the Mi by W/sum(Mi)), and in fact, the code already does that.

As for the R condition, the problem is that moving along such a line can make you run out of the hypercube in another dimension. I can&#039;t really think of a better solution than either moving back along another line or stopping at the border of the hypercube and taking a new line (which only distributes to the dimensions which are not maxed out yet) from there (which sounds like a better / more elegant solution, but is harder to code and should give the same result in the same number of iterations, so it isn&#039;t really that great).</description>
		<content:encoded><![CDATA[<p>@BennyM: Projecting along the normal is the wrong thing to do here. The normal vector of that hypersurface is simply a vector of all ones. Projecting along it means removing the same k from all Oi, it&#8217;s not a proportional resize. What you actually want is the projection along the line (0,M) where 0 is the origin (vector of all zeros) and M is the vector of Mi, i.e. the intersection of that line with the hyperplane. Computing that is trivial (just multiply all the Mi by W/sum(Mi)), and in fact, the code already does that.</p>
<p>As for the R condition, the problem is that moving along such a line can make you run out of the hypercube in another dimension. I can&#8217;t really think of a better solution than either moving back along another line or stopping at the border of the hypercube and taking a new line (which only distributes to the dimensions which are not maxed out yet) from there (which sounds like a better / more elegant solution, but is harder to code and should give the same result in the same number of iterations, so it isn&#8217;t really that great).</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: BennyM</title>
		<link>http://blog.jasondonenfeld.com/35#comment-61</link>
		<dc:creator>BennyM</dc:creator>
		<pubDate>Fri, 28 Nov 2008 22:51:53 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-61</guid>
		<description>Just thinking out loud, and did not look at your code.
I presume somebody has the formula for a hypersurface
O1 + O2 + O3 + … + ON = W, let&#039;s call it X (note that it is like the L_1 norm).
Where there are N axis, and O1 is coordinate on the 1-axis.
From that you can write the formula for the normal to the surface. Given a point (M1, M2, M3, … , MN) you project from this point to the surface along the normal. 
This satisfies the R condition or not. If not, you take the one with the higest value Oi/W&gt;R, call it Oi,1. The surface Oi/W = R for all i, is a hypercube in this space, call it K, and it intersects X in a hypercircle (one dimension less). From Oi,1 you can connect to the hyperplane on this surface &quot;under&quot; Oi,1 via a hypercone. To distribute the excess in column with Oi,1 to the other columns, we need to move to the point on the hypercircle that increases all other values equally. The analogy in 3D would be if z value is too large, you move via a cone to a lower z value along the plane that is above the first bissectrice of the xy plane. 

Still following? I cannot guarantee correctness, for that I would need a piece of paper and a pen, but my above reasoning would lead me to think that geometrically it can be done by solving some systems to find the intersection points. So just a library to solve linear system of equation would be needed, but those are very fast.</description>
		<content:encoded><![CDATA[<p>Just thinking out loud, and did not look at your code.<br />
I presume somebody has the formula for a hypersurface<br />
O1 + O2 + O3 + … + ON = W, let&#8217;s call it X (note that it is like the L_1 norm).<br />
Where there are N axis, and O1 is coordinate on the 1-axis.<br />
From that you can write the formula for the normal to the surface. Given a point (M1, M2, M3, … , MN) you project from this point to the surface along the normal.<br />
This satisfies the R condition or not. If not, you take the one with the higest value Oi/W&gt;R, call it Oi,1. The surface Oi/W = R for all i, is a hypercube in this space, call it K, and it intersects X in a hypercircle (one dimension less). From Oi,1 you can connect to the hyperplane on this surface &#8220;under&#8221; Oi,1 via a hypercone. To distribute the excess in column with Oi,1 to the other columns, we need to move to the point on the hypercircle that increases all other values equally. The analogy in 3D would be if z value is too large, you move via a cone to a lower z value along the plane that is above the first bissectrice of the xy plane. </p>
<p>Still following? I cannot guarantee correctness, for that I would need a piece of paper and a pen, but my above reasoning would lead me to think that geometrically it can be done by solving some systems to find the intersection points. So just a library to solve linear system of equation would be needed, but those are very fast.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jason Donenfeld</title>
		<link>http://blog.jasondonenfeld.com/35#comment-60</link>
		<dc:creator>Jason Donenfeld</dc:creator>
		<pubDate>Fri, 28 Nov 2008 22:28:53 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-60</guid>
		<description>@Esben
Oi also must be proportional to Mi/(M1 + M2 + M3 ... + MN), unless it hits the maximum R. As for your += vs =, take another look at the code. This code does its job very well, but I don&#039;t want to rely on iteration.

@VPeric
When determining the ratio, precession does matter to a somewhat significant degree because we multiply ratios with an arbitrarily large width to determine pixels. 

The problem is that when redistributing the difference between R and the real ratio, you may push the other columns over R, which means another iterative pass must be done to catch this.

@Florian
Thinking of it as a maximization problem... hmm. Thanks for the links.</description>
		<content:encoded><![CDATA[<p>@Esben<br />
Oi also must be proportional to Mi/(M1 + M2 + M3 &#8230; + MN), unless it hits the maximum R. As for your += vs =, take another look at the code. This code does its job very well, but I don&#8217;t want to rely on iteration.</p>
<p>@VPeric<br />
When determining the ratio, precession does matter to a somewhat significant degree because we multiply ratios with an arbitrarily large width to determine pixels. </p>
<p>The problem is that when redistributing the difference between R and the real ratio, you may push the other columns over R, which means another iterative pass must be done to catch this.</p>
<p>@Florian<br />
Thinking of it as a maximization problem&#8230; hmm. Thanks for the links.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Florian</title>
		<link>http://blog.jasondonenfeld.com/35#comment-59</link>
		<dc:creator>Florian</dc:creator>
		<pubDate>Fri, 28 Nov 2008 22:12:47 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-59</guid>
		<description>Welcome to the wonderful world of linear programming. Your Problem is:

Maximize z = C1O1+...+CnOn with Ci = Mi/(M1+...+Mn)
Subject to
   Oi &lt;= Mi
   O1+...+On &lt;= W
  -O1-...-On &lt;= W
   Oi &lt;= W*R


See http://en.wikipedia.org/wiki/Simplex_algorithm
and http://en.wikipedia.org/wiki/Linear_programming for a starting point.</description>
		<content:encoded><![CDATA[<p>Welcome to the wonderful world of linear programming. Your Problem is:</p>
<p>Maximize z = C1O1+&#8230;+CnOn with Ci = Mi/(M1+&#8230;+Mn)<br />
Subject to<br />
   Oi &lt;= Mi<br />
   O1+&#8230;+On &lt;= W<br />
  -O1-&#8230;-On &lt;= W<br />
   Oi &lt;= W*R</p>
<p>See <a href="http://en.wikipedia.org/wiki/Simplex_algorithm" rel="nofollow">http://en.wikipedia.org/wiki/Simplex_algorithm</a><br />
and <a href="http://en.wikipedia.org/wiki/Linear_programming" rel="nofollow">http://en.wikipedia.org/wiki/Linear_programming</a> for a starting point.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: VPeric</title>
		<link>http://blog.jasondonenfeld.com/35#comment-58</link>
		<dc:creator>VPeric</dc:creator>
		<pubDate>Fri, 28 Nov 2008 22:08:11 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-58</guid>
		<description>^Err, I got a bit carried away with the variables there: t should use suggestedratio, and you&#039;d need a &quot;suggestedwidth[i]=t&quot; under the &quot;remain +=R-t&quot; line.</description>
		<content:encoded><![CDATA[<p>^Err, I got a bit carried away with the variables there: t should use suggestedratio, and you&#8217;d need a &#8220;suggestedwidth[i]=t&#8221; under the &#8220;remain +=R-t&#8221; line.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: VPeric</title>
		<link>http://blog.jasondonenfeld.com/35#comment-57</link>
		<dc:creator>VPeric</dc:creator>
		<pubDate>Fri, 28 Nov 2008 22:03:45 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-57</guid>
		<description>I&#039;m not exactly sure on the math you give, but I think I understand the problem enough to attempt a solution.

First of all, since we&#039;re dealing with pixels, it doesn&#039;t really have to be _that_ precise. With that in mind, here&#039;s a simple algorithm that needs only two passes: 

remain=0;
for (i=0; i&lt;n; i++){ //n - number of columns
t=suggestedwidth[i]/W;
if (t&lt;R){
  remain += R-t;
} else {
  //optionally, remember the index i
  suggestedwidth[i]=R;
}
}
remain = remain*W //convert ratio to pixels
//distribute pixels among all columns equally, or just to those who were too short, if you remembered the index above

Yes, I&#039;m sure you could&#039;ve thought of that yourself, but the point is that something like that is a suitable amount of approximation. And, even if it isn&#039;t particulary fast, coding it like this would make it _immensly_ easier to add an additional column or three. 

Hope that helps; I&#039;ll stop by if I think of an actual mathematical solution!</description>
		<content:encoded><![CDATA[<p>I&#8217;m not exactly sure on the math you give, but I think I understand the problem enough to attempt a solution.</p>
<p>First of all, since we&#8217;re dealing with pixels, it doesn&#8217;t really have to be _that_ precise. With that in mind, here&#8217;s a simple algorithm that needs only two passes: </p>
<p>remain=0;<br />
for (i=0; i&lt;n; i++){ //n &#8211; number of columns<br />
t=suggestedwidth[i]/W;<br />
if (t&lt;R){<br />
  remain += R-t;<br />
} else {<br />
  //optionally, remember the index i<br />
  suggestedwidth[i]=R;<br />
}<br />
}<br />
remain = remain*W //convert ratio to pixels<br />
//distribute pixels among all columns equally, or just to those who were too short, if you remembered the index above</p>
<p>Yes, I&#8217;m sure you could&#8217;ve thought of that yourself, but the point is that something like that is a suitable amount of approximation. And, even if it isn&#8217;t particulary fast, coding it like this would make it _immensly_ easier to add an additional column or three. </p>
<p>Hope that helps; I&#8217;ll stop by if I think of an actual mathematical solution!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Esben Mose  Hansen</title>
		<link>http://blog.jasondonenfeld.com/35#comment-56</link>
		<dc:creator>Esben Mose  Hansen</dc:creator>
		<pubDate>Fri, 28 Nov 2008 21:59:10 +0000</pubDate>
		<guid isPermaLink="false">http://blog.jasondonenfeld.com/?p=35#comment-56</guid>
		<description>I don&#039;t think I understand the question, nor the code. Is it working, or am I tired? The do{....} while (b) will only executed either once (if any of the ifs are true) or forever otherwise.	 It also seems to me that the 3rd and 4th line if your ifs should be += rather than just =.

You seem to define three (types of constraints ) (here written for your example of three due to the limits of the medium)
O1+O2+O3=W
  O1&lt;=WR
  O2&lt;=WR
  O3&lt;=WR
  O1&lt;=M1
  O2&lt;=M2
  O3&lt;=M3

Am I right?</description>
		<content:encoded><![CDATA[<p>I don&#8217;t think I understand the question, nor the code. Is it working, or am I tired? The do{&#8230;.} while (b) will only executed either once (if any of the ifs are true) or forever otherwise.	 It also seems to me that the 3rd and 4th line if your ifs should be += rather than just =.</p>
<p>You seem to define three (types of constraints ) (here written for your example of three due to the limits of the medium)<br />
O1+O2+O3=W<br />
  O1&lt;=WR<br />
  O2&lt;=WR<br />
  O3&lt;=WR<br />
  O1&lt;=M1<br />
  O2&lt;=M2<br />
  O3&lt;=M3</p>
<p>Am I right?</p>
]]></content:encoded>
	</item>
</channel>
</rss>
