Algorithm to create all possible combinations

荒凉一梦 提交于 2019-12-02 02:14:20

问题


I'm writing a spares grid code and need to combine N 1-dimensional grid points (written in vector form) into the an array of all possible points. For example one can mix two vectors (a,b) with (c,d,e) giving the following points:

(a,c) (a,d) (a,e) (b,c) (b,d) (b,e)

Matlab has a function called combvec:

http://www.mathworks.co.uk/help/nnet/ref/combvec.html

I'm writing this code in FORTRAN however I can't find the underlying algorithm. The code needs to take in N (N>1) vectors (i.e 2,3...N) and each can be a different length. Does anyone know of an algorithm?


回答1:


I don't know Fortran, but since you say you can't find the underlying algorithm I'm assuming you will be able to write this yourself once you know the algorithm. It's quite easy actually. The pseudocode would be something like this (assuming there are no duplicates):

index = 0   ! or 1
for each element in first vector
    for each element in second vector
        matrix(index,1) = current element of first vector
        matrix(index,2) = current element of second vector
        index = index + 1
    end for
end for

This should give you a matrix similar to the one you would get using combvec. There are probably more efficient ways to do this, but as I don't know the details of Fortran I can't help you there unfortunately. In Matlab you would of course vectorize this.

Good luck =)




回答2:


The following function should do what you want, I think. It is as simple as possible, taking as input a rank 1 array containing the cardinalities of the data sets and returning a rank 2 array, one column for each set, containing the indices for that set. The expression 1 + mod((i-1)/rep, N) represents the ith element of a sequence of integers 1,2,...,N, with each element repeated rep times.

! (requires explicit interface)
pure function cartprod(v) result(cp)
  integer, intent(in) :: v(1:)
  integer :: cp(product(v), size(v,1))

  integer :: i, j, p, rep

  p = product(v)

  do j = 1, size(v,1) 
    rep = p / product(v(1:j))
    do i = 1, p
      cp(i,j) = 1 + mod((i-1)/rep, v(j))
    enddo
  enddo
end function

Suppose you have defined a dynamic length vector as follows, you could directly obtain the matrix of combinations:

module dynamic_vector
  implicit none

  type :: d_vector
    integer, allocatable :: val(:)
  end type

contains

  pure function combvec(v) result(cv)
    type(d_vector), intent(in) :: v(1:)
    integer, allocatable :: cv(:,:)

    integer :: i, j, prod, rep, len, sizes(size(v,1))

    len = size(v,1)

    ! Determine sizes of the vectors, loop is necessary because we may not
    ! reference v%val if v is an array and val is allocatable.
    do i = 1, len
      sizes(i) = size(v(i)%val,1)
    enddo

    prod = product(sizes)

    ! Allocate and fill the output matrix
    allocate(cv(prod, len))

    do j = 1, len
      rep = prod / product(sizes(1:j))
      do i = 1, prod
        cv(i,j) = v(j)%val(1 + mod((i-1)/rep, sizes(j)))
      enddo
    enddo
  end function
end module

A short test program:

program test
  use dynamic_vector
  implicit none

  type(d_vector) :: foo(2)
  integer :: i, bar(:,:)
  allocatable :: bar

  allocate(foo(1)%val, source = [1,2])
  allocate(foo(2)%val, source = [3,4,5])

  bar = combvec(foo)
  write(*,'(2(I0,X))') (bar(i,:), i = 1, 6)
end program

Result:

1 3
1 4
1 5
2 3
2 4
2 5


来源:https://stackoverflow.com/questions/24364332/algorithm-to-create-all-possible-combinations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!