简体   繁体   中英

Traversal of an n-dimensional space

I'm trying to write an algorithm that will let me iterate over all desired points within an n-dimensional space to find the minimum of a function f(x) where x is a vector of size n.

Obviously, searching a 2-d or 3-d space is fairly straightforward, you can simply do:

for(int i = 0; i < x; i++) {
    for(int j = 0; j < y; j++) {
        //and so on for however many dimensions you want

Unfortunately, for my problem, the dimensionality of the space is not fixed (I'm writing a generalised minimum finder for many functions in a statistical program) and so I'd have to write loops for each value of n I want to use - which might ultimately be rather large.

I've been trying to get my head around how I could do this using recursion but can't quite see the solution - although I'm sure there is one there.

The solution doesn't have to be recursive, but it must be general and efficient (the inner most line in that nested loop is going to get called an awful lot...).

The way I'm representing the volume to search is a 2d array of double:

double[][] space = new double[2][4];

This would represent a 4d space with the minimum and maximum bound in each dimension in position 0 or 1 of the array, respectively. Eg:

dim         0   1   2   3
    min(0):-10  5  10  -0.5
    max(1): 10 55  99   0.2

Any ideas?

Here is the general idea:

interface Callback {
   void visit(int[] p); // n-dimensional point
}

// bounds[] - each number the limits iteration on i'th axis from 0 to bounds[i]
// current - current dimension
// callback - point
void visit(int[] bounds, int currentDimension, int[] p, Callback c) {
   for (int i = 0; i < bounds[currentDimension]; i++) {
        p[currentDimension] = i;
        if (currentDimension == p.length - 1) c.visit(p);
        else visit(bounds, currentDimension + 1, p, c);
   }
}

/// now visiting
visit(new int[] {10, 10, 10}, 0, new int[3], new Callback() {
   public void visit(int[] p) {
        System.out.println(Arrays.toString(p));
   }
});

I'd stick with reucrsion, and use Object as a parameter, with an extra parameter of dim , and cast it when you reach a depth of 1 to the relevant array [in my example, it is an int[] ]

public static int getMin(Object arr, int dim) {
    int min = Integer.MAX_VALUE;
    //stop clause, it is 1-dimensional array - finding a min is trivial
    if (dim == 1) { 
        for (int x : ((int[])arr)) {
            min = Math.min(min,x);
        }
    //else: find min among all elements in an array of one less dimenstion.
    } else { 
        for (Object o : ((Object[])arr)) { 
            min = Math.min(min,getMin(o,dim-1));
        }
    }
    return min;
}

example:

public static void main(String[] args) {
    int[][][] arr = { { {5,4},{2}, {35} } , { {2, 1} , {0} } , {{1}}};
    System.out.println(getMin(arr, 3));
}

will produce:

0

The advantage of this approach is no need for any processing of the array - you just send it as it is, and send the dimension as a parameter.
The downside - is type [un]safety, since we dynamically cast the Object to an array.

Another option is to iterate from 0 to x*y*z*... like you do when converting a number between binary and decimal representations. This is a non-recursive solution, so you won't run into performance issues.

ndims = n;
spacesize = product(vector_sizes)
int coords[n];

for (i = 0; i < spacesize; i++) {
    k = i;
    for (j = 0; j < ndims; j++ ) {
         coords[j] = k % vector_sizes[j];
         k /= vector_sizes[j];
    }
    // do something with this element / these coords
}

n-dimensional arrays can be flattened into one-dimensional arrays. What you need is to do the math for these things:

  • Calculate the size of the unidimensional array needed.
  • Figure out the formulas needed to translate back from the n-dimensional index to the unidimensional one.

This is what I'd do:

  • Represent n-dimensional array sizes and indexes as int[] . So, the size of a 5x7x13x4 4-dimensional array represented as the 4-element array `{ 5, 7, 13, 4 }'.
  • An n-dimensional array is represented as a unidimensional array whose size is the product of the sizes of each of the dimensions. So a 5x7x13x4 array would be represented as a flat array of size 1,820.
  • An n-dimensional index is translated into a unique index in the flat array by multiplication and addition. So, the index <3, 2, 6, 0> into the 5x7x13x4 array is translated as 3 + 2*5 + 6*5*7 + 0*5*7*13 == 223 . To access that 4-dimensional index, access index 223 in the flat array.
  • You can also translate backwards from flat array indexes to n-dimensional indexes. I'll leave that one as an exercise (but it's basically doing n modulo calculations).

Isn't the function just:

Function loopDimension(int dimensionNumber)
    If there is no more dimension, stop;
    for(loop through this dimension){
         loopDimension(dimensionNumber + 1);
    }

This runs through a List of List of values (Integers) and picks the minimum of each List:

import java.util.*;
/**
    MultiDimMin

    @author Stefan Wagner
    @date Fr 6. Apr 00:37:22 CEST 2012

*/
public class MultiDimMin
{
    public static void main (String args[])
    {
        List <List <Integer>> values = new ArrayList <List <Integer>> ();
        Random r = new Random ();
        for (int i = 0; i < 5; ++i)
        {   
            List<Integer> vals = new ArrayList <Integer> ();            
            for (int j = 0; j < 25; ++j)
            {   
                vals.add (100 - r.nextInt (200));   
            }
            values.add (vals);
        }
        showAll (values);
        List<Integer> res = multiDimMin (values);
        show (res);
    }

    public static int minof (List <Integer> in)
    {
        int res = in.get (0);
        for (int v : in)
            if (res > v) res = v;
        return res;
    }

    public static List<Integer> multiDimMin (List <List <Integer>> in)
    {
        List<Integer> mins = new ArrayList <Integer> ();
        for (List<Integer> li : in) 
            mins.add (minof (li));
        return mins; 
    }

    public static void showAll (List< List <Integer>> lili)
    {
        for (List <Integer> li : lili) {
            show (li);
            System.out.println ();
        }
    }   

    public static void show (List <Integer> li)
    {
        for (Integer i: li) {
            System.out.print (" " + i);
        }
        System.out.println ();
    }   
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM