for { set j 0 } { $j < $jmax } { incr j } { for { set i 0 } { $i < $imax } { incr i } { ... check the properties ... } }The problem is that you need to specify the upper limits and that you will spend a lot of time in regions far from the origin, whereas in many cases, you will be interested mostly in points near the origin.This becomes worse with increasing dimensions.Is there an alternative? Yes, you could enumerate the points like this:
| . | . (5)--(8)-- | . . | . . (2)--(4)--(7)-- | . . . | . . . (0)--(1)--(3)--(6)--So that:
- 0 is associated with (0,0)
- 1 is associated with (1,0)
- 2 is associated with (0,1)
- 3 is associated with (2,0)
- 4 is associated with (1,1)
- ...
namespace eval ::IntegerGrid { variable current 0 } proc ::IntegerGrid::enum2d {} { variable current incr current split2d $current } proc ::IntegerGrid::enum3d {} { foreach {x yz} [enum2d] {break} foreach {y z} [split2d $yz] {break} return [list $x $y $z] } proc ::IntegerGrid::enum4d {} { # # To avoid double points in the origin # set xy 0 set yw 0 while { $xy == 0 || $zw == 0 } { foreach {xy zw} [enum2d] {break} } foreach {x y} [split2d $xy] {break} foreach {z w} [split2d $zw] {break} return [list $x $y $z $w] } proc ::IntegerGrid::split2d {number} { set ncount 1 while { $number > $ncount } { set number [expr {$number-$ncount}] incr ncount } set x [expr {$ncount-$number}] set y [expr {$ncount-$x-1}] list $x $y } # main -- # Enumerate the points in a ball |x| < 5 in 4D # Estimating the space that we need to examine # is trifle difficult, but take it wider than # necessary to be sure # # set rad 0 set count 0 while { $rad < 10 } { foreach {x y z w} [::IntegerGrid::enum4d] {break} set rad [expr {sqrt($x*$x+$y*$y+$z*$z+$w*$w)}] if { $rad < 5 } { puts "$x $y $z $w -- $rad" incr count } } puts "$count points found" # # Using the straightforward approach ... # set count 0 for { set x 0 } { $x < 5 } { incr x } { for { set y 0 } { $y < 5 } { incr y } { for { set z 0 } { $z < 5 } { incr z } { for { set w 0 } { $w < 5 } { incr w } { set rad [expr {sqrt($x*$x+$y*$y+$z*$z+$w*$w)}] if { $rad < 5 } { puts "$x $y $z $w -- $rad" incr count } } } } } puts "$count points found"
Lars H: On the issue of choosing a termination radius in the 4D example, the limit 10 is actually optimal (at least with respect to rational points in the ball; the integral points may allow a stricter bound, but it's not realistic to do such analysis in preparation for a simple enumeration such as this one). To see this, consider the point {2.5 2.5 2.5 2.5}. This is at distance 5 from the origin, so it lies on the boundary of the ball. The sum of its coordinates is 10, so no hyperplane $x+$y+$z+$w=$n with $n<10 falls outside the ball. Since [enum4d] walks through each such hyperplane before it proceeds to the next one, it is necessary to allow processing of $n=9 and thus also e.g. the point {9 0 0 0}. The least integral radius admitting this point is indeed 10.