Murphy still winning

new topic     » topic index » view thread      » older message » newer message

Pete and all:
I corrected the small bug you mentioned. I also found another bug and
corrected it. I made a slight improvement. But, using sequences such as the
one included in the listing, the program has to actually backtrack and so it
uses much time.
Murphy wins. I was not able to find more improvements and decided to let
things stand as they are now.
But it is worth considering that, for random numbers, or better, for data
that is not especially prepared to defeat the algorithm, it is really fast
even with huge quantities of numbers.
Regards.

The "omega" version:

--Group numbers into two groups such that their sums are as close as
possible
--R. M. Forno 2003/04/17
include sort.e
include get.e
include misc.e
include machine.e

integer Last, Lendata, Bestlast
atom Lowgoal, Highgoal, Val, Bestval, Totval, Limit, Bound
sequence Data, Index, Accum, Bestind

set_rand(1)

function Mcd2(integer d, integer r)
    integer x
    while r do
    x = remainder(d, r)
    d = r
    r = x
    end while
    return d
end function

function Mcd(sequence s)
    integer len, r
    len = length(s)
    r = s[len]
    for i = len - 1 to 1 by -1 do
    if r = 1 then
        return r
    end if
    r = Mcd2(r, s[i])
    end for
    return r
end function

function readseq()
--Read a sequence of integers from the keyboard or from a redirected file
    sequence s, r
    s = {}
    while 1 do
    r = get(0)
    if r[1] != GET_SUCCESS or not integer(r[2]) then
        exit
    end if
    s &= r[2]
    end while
    return s
end function

procedure outputresult()
--Output resulting partitions
    sequence aux
    aux = repeat(0, Lendata)
    for i = 1 to Lendata do
    aux[i] = i
    end for
    for i = 1 to Bestlast do
    aux[Bestind[i]] = 0
    end for
    printf(1, "Best solution values: %d %d\n", {Bestval, Totval - Bestval})
    puts(1, "Partition 1:\n")
    for i = 1 to Bestlast do
    printf(1, "%d ", Data[Bestind[i]])
    end for
    puts(1, '\n')
    puts(1, "Partition 2:\n")
    for i = 1 to Lendata do
    if aux[i] then
        printf(1, "%d ", Data[aux[i]])
    end if
    end for
    puts(1, '\n')
end procedure

function recurse()
    integer ind, r, dat, i1
    if Val > Highgoal then --Impossible to get better values
    return 0
    elsif Val < Lowgoal then --Try to go ahead
    if Val >= Bound then
        if Val > Bestval then --Test for better value
        Bestval = Val --Update best value and corresponding indexes
        Bestlast = Last
        Bestind = Index
        end if
    end if
    if Val > Limit then --Impossible to get better values
        return 0
    end if
    ind = Index[Last] --Go to next data item
    while 1 do
        i1 = ind --Previous
        ind += 1
        if ind > Lendata then --End of data vector
        return 0
        end if
        if Val + Accum[ind] <= Bestval then --Impossible to get better value
        return 0
        end if
        dat = Data[ind]
        if dat != Data[i1] or Index[Last] = i1 then --Skip repetition
        Last += 1 --Try next index
        Index[Last] = ind
        Val += dat
        r = recurse()
        if r then --Best possible value found
            return 1
        end if
        Val -= dat --Restore previous value
        Last -= 1
        end if
    end while
    else
    Bestval = Val --Either Val = Lowgoal or Val = Highgoal
    Bestlast = Last
    Bestind = Index
    return 1 --Indicate best possible value found
    end if
end function

procedure optim()
    integer r
    Bestval = 0
    Last = 1
    Bestlast = 1
    Index[1] = 1
    Val = Data[1]
    Limit = Highgoal - Data[Lendata]
    Bound = Lowgoal - Data[1]
    Bestind = Index
    r = recurse()
    if Bestval = 0 then
    Bestval = Data[1]
    end if
end procedure

function genrand(integer n, integer m)
    sequence s
    s = 14 * rand(repeat(n, m))
    s[1] += 1
    s[length(s)] += 1
    return s
end function

procedure main()
    atom t
    integer a, b, mcd, r
    a = 10000
    b = 28
--  Data = readseq()
    Data = genrand(a, b)
--  Data = {111, 9, 9, 9, 9, 9, 5, 1, 1, 1}
    t = time()
    Lendata = length(Data)
    Index = repeat(0, Lendata)
    if Lendata = 0 then
    Bestlast = 0
    Totval = 0
    Bestval = 0
    elsif Lendata = 1 then
    Bestlast = 1
    Bestind = {1}
    Totval = Data[1]
    Bestval = Totval
    else
    Data = reverse(sort(Data))
    Accum = Data
    for i = Lendata to 2 by -1 do
        Accum[i - 1] += Accum[i]
    end for
    Totval = Accum[1]
    Lowgoal = floor(Totval * 0.5)
    Highgoal = - floor(- Totval * 0.5)
    mcd = Mcd(Data)
    Lowgoal -= remainder(Lowgoal, mcd)
    r = remainder(Highgoal, mcd)
    if r then
        Highgoal += mcd - r
    end if
    if Totval - Highgoal < Lowgoal then
        Lowgoal = Totval - Highgoal
    end if
    if Totval - Lowgoal > Highgoal then
        Highgoal = Totval - Lowgoal
    end if
    printf(2, "Lowgoal = %d, Highgoal = %d\n", {Lowgoal, Highgoal})
    optim()
    end if
    printf(2, "n = %d m = %d Sum1 = %d Sum2 = %d Time: %f\n",
        {a, b, Bestval, Totval - Bestval, time() - t})
    outputresult()
end procedure

main()

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu