Как я решаю ряд ограничений в Perl?

Вам нужно проанализировать рекламные объявления, чтобы получить тип аудиообъекта, индекс частоты и количество каналов. Затем напишите аудио конкретный конфиг. https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Audio_Specific_Config

9
задан vladr 22 February 2009 в 23:12
поделиться

6 ответов

Основная проблема в этой проблеме оптимизации является математической по своей природе.

Ваша цель, поскольку я могу вывести из Вашего определения gen_abc метод, должен сократить Ваше пространство поиска путем нахождения ограничения интервалов для различных переменных ($a, $b и т.д.)

Лучшая стратегия состоит в том, чтобы извлечь как много линейных ограничений из Вашего полного набора ограничений, попытаться вывести границы (использующий линейные методы программирования, посмотрите ниже), затем возобновите исчерпывающий (или недетерминированный) эмпирические тесты против сокращенного переменного пространства.

Типичная линейная проблема программирования имеет форму:

minimize (maximize) <something>
subject to <constraints>

Например, учитывая три переменные, a, b и c, и следующие линейные ограничения:

<<linear_constraints>>::
  $a < $b
  $b > $c
  $a > 0
  $c < 30

Можно найти верхние и нижние границы для $a, $b и $c следующим образом:

lower_bound_$a = minimize $a subject to <<linear_constraints>>
upper_bound_$a = maximize $a subject to <<linear_constraints>>
lower_bound_$b = minimize $b subject to <<linear_constraints>>
upper_bound_$b = maximize $b subject to <<linear_constraints>>
lower_bound_$c = minimize $c subject to <<linear_constraints>>
upper_bound_$c = maximize $c subject to <<linear_constraints>>

В Perl можно использовать Математику:: LP к этой цели.


ПРИМЕР

Линейное ограничение имеет форму"C eqop C1×$V1 ± C2×$V2 ± C3×$V3 ...", где

  • eqop один из <, >, ==, >=, <=
  • $V1, $V2 и т.д. переменные, и
  • C, C1, C2 и т.д. константы, возможно равняются 0.

Например, данный...

$a < $b
$b > $c
$a > 0
$c < 30

... переместите все переменные (с их коэффициентами) слева от неравенства и одиноких констант направо от неравенства:

$a - $b       <  0
     $b - $c  >  0
$a            >  0
          $c  < 30

... и скорректируйте ограничения так, чтобы только =, <= и >= (в) равенствах используются (принятие дискретных т.е. целочисленных значений для наших переменных):

  • '... <C' становится '... <= C-1'
  • '...> C' становится '...> = C+1'

... то есть,

$a - $b       <= -1
     $b - $c  >=  1
$a            >=  1
          $c  <= 29

... затем запишите что-то вроде этого:

use Math::LP qw(:types);             # imports optimization types
use Math::LP::Constraint qw(:types); # imports constraint types

my $lp = new Math::LP;

my $a  = new Math::LP::Variable(name => 'a');
my $b  = new Math::LP::Variable(name => 'b');
my $c  = new Math::LP::Variable(name => 'c');

my $constr1 = new Math::LP::Constraint(
    lhs  => make Math::LP::LinearCombination($a, 1, $b, -1), # 1*$a -1*$b
    rhs  => -1,
    type => $LE,
);
$lp->add_constraint($constr1);
my $constr2 = new Math::LP::Constraint(
    lhs  => make Math::LP::LinearCombination($b, 1, $c, -1), # 1*$b -1*$c
    rhs  => 1,
    type => $GE,
);
$lp->add_constraint($constr2);

...

my $obj_fn_a = make Math::LP::LinearCombination($a,1);
my $min_a = $lp->minimize_for($obj_fn_a);
my $max_a = $lp->maximize_for($obj_fn_a);

my $obj_fn_b = make Math::LP::LinearCombination($b,1);
my $min_b = $lp->minimize_for($obj_fn_b);
my $max_b = $lp->maximize_for($obj_fn_b);

...

# do exhaustive search over ranges for $a, $b, $c

Конечно, вышеупомянутое может быть обобщено к любому количеству переменных V1, V2... (например. $a, $b, $c, $d...), с любыми коэффициентами C1, C2... (например,-1, 1, 0, 123, и т.д.) и любые постоянные величины C (например,-1, 1, 30, 29, и т.д.), если можно проанализировать ограничительные выражения в соответствующее матричное представление, такие как:

   V1  V2  V3     C
[ C11 C12 C13 <=> C1 ]
[ C21 C22 C23 <=> C2 ]
[ C31 C32 C33 <=> C3 ]
... ... ... ... ... ...

При применении к примеру Вы обеспечили,

  $a  $b  $c     C
[  1  -1   0 <= -1 ]   <= plug this into a Constraint + LinearCombination
[  0   1  -1 >=  1 ]   <= plug this into a Constraint + LinearCombination
[  1   0   0 >=  1 ]   <= plug this into a Constraint + LinearCombination
[  0   0   1 <= 29 ]   <= plug this into a Constraint + LinearCombination

Примечание:

Как примечание стороны, при выполнении недетерминированный (rand- базирующийся) тесты, это может или не может быть хорошей идеей отслеживать (например, в хеше) который ($a,$b,$c) кортежи были уже протестированы, чтобы не тестировать их снова, если и только если:

  • протестированный метод является более дорогим, чем поиск хеша (дело обстоит не так с кодом кода, который Вы предоставили выше, но можете, или может не быть проблема с Вашим реальным кодом),
  • хеш не вырастет до огромных пропорций (или все переменные, связываются конечными интервалами, продуктом которых является разумное число - в этом случае проверка, что размер хэша может указать, исследовали ли Вы полностью все пространство или не - или можно периодически очищать хеш так, по крайней мере, для одного временного интервала за один раз, у Вас действительно есть некоторое обнаружение коллизий.)
    • в конечном счете, если Вы думаете, что вышеупомянутое могло относиться к Вам, Вы можете время различные опции реализации (с и без хеша) и видеть, стоит ли это реализовать или нет.
14
ответ дан 4 December 2019 в 11:44
поделиться

Я использую Данные:: Ограничение. Вы пишете небольшие подпрограммы, которые реализуют отдельные ограничения, затем последовательно применяют все ограничения, которые Вы хотите. Я говорю об этом немного в Освоении Perl в "Динамических Подпрограммах" глава.

use Data::Constraint;

Data::Constraint->add_constraint(
    'a_less_than_b',
    run         => sub { $_[1] <  $_[2] },
    description => "a < b",
    );

Data::Constraint->add_constraint(
    'b_greater_than_c',
    run         => sub { $_[2] >  $_[3] },
    description => "b > c",
    );

Data::Constraint->add_constraint(
    'a_greater_than_0',
    run         => sub { $_[1] > 0 },
    description => "a > 0",
    );

Data::Constraint->add_constraint(
    'c_less_than_30',
    run         => sub { $_[3] < 30 },
    description => "c < 30",
    );

Data::Constraint->add_constraint(
    'a_is_odd_between_10_18',
    run         => sub { 
        return 1 if( $_[1] < 10 or $_[1] > 18);
        return 0 unless $_[1] % 2,
        },
    description => "a is odd between 10 and 18",
    );

for ( 1 .. 10 )
    {
    my( $a, $b, $c ) = gen_abc(); 
    print "a = $a | b = $b | c = $c\n";

    foreach my $name ( Data::Constraint->get_all_names )
        {
        print "\tFailed $name\n"
            unless Data::Constraint->get_by_name( $name )->check( $a, $b, $c ),
        }
    }

sub gen_abc {
    my $c = int rand 30;
    my $b = int rand $c;
    my $a = int rand $b;
    return ($a, $b, $c);
}

Выполнение его, этот путь означает, что легко осмотреть результат для наблюдения то, что перестало работать вместо полного отказа:

a = 2 | b = 4 | c = 5
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 0 | c = 2
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 0 | c = 2
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c
a = 7 | b = 14 | c = 25
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 0 | c = 29
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 0 | c = 20
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 4 | c = 22
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c
a = 4 | b = 16 | c = 28
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 22 | c = 26
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c
a = 0 | b = 3 | c = 6
    Failed a_greater_than_0
    Failed a_less_than_b
    Failed b_greater_than_c

Если Вы хотите что-то больше хардкора, мой Кирпичный модуль обрабатывает деревья ограничений, включая сокращение и ветвление. Эти вещи имеют смысл для больших систем, где Вы будете смешивать и соответствовать различным ограничениям для различных ситуаций, так как большая часть кода настраивает ограничительные объекты. Если у Вас только есть своя одна ситуация, Вы, вероятно, просто хотите придерживаться с тем, что Вы имеете.

Удача, :)

2
ответ дан 4 December 2019 в 11:44
поделиться

кажется что Simo:: Ограничьте то, что Вы хотите

0
ответ дан 4 December 2019 в 11:44
поделиться

Я не уверен, что Вы собираетесь найти простой ответ на это (хотя я хотел бы быть доказанным неправым!).

Кажется, что Ваша проблема хорошо подошла бы для генетического алгоритма. Функцию фитнеса должно быть легко записать, просто выиграть 1 за каждое удовлетворенное ограничение, 0 иначе. AI:: Генетический, кажется, модуль, который мог помочь Вам, и написать код и понять то, что необходимо записать.

Это должно быть быстрее, чем метод грубой силы.

1
ответ дан 4 December 2019 в 11:44
поделиться

Я вместо этого создал бы алгоритм, который генерирует набор действительных списков, случайным образом сгенерированных или не (это должно быть тривиально), запишите им в файл и затем используйте тот файл для питания тестовой программы, таким образом, он может случайным образом выбрать любой список, он хочет.

0
ответ дан 4 December 2019 в 11:44
поделиться

"Реальный" ответ потребовал бы парсинга выражений и обоснования об отношениях. За исключением этого, я предложил бы использовать систематический обход пространства значений, вместо того, чтобы просто пробовать значения наугад. Например,

my $count = 0;
for (my $c = 0; $c < 30 && $count < $SOMELIMIT; ++$c) {
    # check all other constraints on only $c here
    # next if any fail
    for (my $b = $c + 1; $b < $UPPERLIMIT && $count < $SOMELIMIT; ++$b) {
        # check all other constraints on only $b and $c here
        # next if any fail
        for (my $a = 1; $a < $b && $count < $SOMELIMIT; ++$a) {
            #check all remaining constraints on $a, $b, and $c here
            # next if any fail
            # now use surviving combinations
            ++$count;
        }
    }
}

Я поместил переменную с большинством отдельных ограничений на наиболее удаленном уровне, затем самом ограниченном следующий, и т.д.

По крайней мере, с этой структурой Вы не протестируете ту же комбинацию многократно (как случайная версия, очень вероятно, сделает), и если Вы наблюдаете, что она работает, можно видеть, что шаблоны появляются, который позволяет Вам прервать выполнение.

1
ответ дан 4 December 2019 в 11:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: