#!/usr/bin/perl use strict; use FileHandle; use Getopt::Mixed; use vars qw ($opt_sequenced $opt_numeric $opt_simple $opt_constraints $opt_preferences $opt_derived $opt_bounded $opt_fixed $opt_time $opt_soft $opt_exponential $opt_weight $opt_range $opt_seed $opt_n $opt_skip $opt_cp $opt_sat $opt_cut $opt_zinc $opt_comment $opt_info $opt_ipc); Getopt::Mixed::getOptions("sequenced numeric simple constraints preferences derived bounded=s fixed time soft exponential weight=s range=s seed=s n=s skip=s cp sat cut zinc comment info ipc=s"); my $infilename = shift; # random number generator (linear congruential) my $rng_seed = 100000000; if (defined $opt_seed) { $rng_seed = $opt_seed; } sub random { # x = ((a * x) + b) % mod; $rng_seed = ((23 * $rng_seed) % 100000001); return $rng_seed; } my $i = random(); print "Random number 1: $i\n"; $i = random(); print "Random number 2: $i\n"; $i = random(); print "Random number 3: $i\n"; # extract infile basename my $basename; $_ = $infilename; while (/([^\/]*\/)(.+)/) { $_ = $2; } if (/([^\.]+)\.(.*)/) { $basename = $1; } else { $basename = $_; } print STDERR "reading file: $infilename (basename = \"$basename\")\n"; my $mode = 0; my $problem_name; my $products = 0; my $orders = 0; my %includes = (); my $current_order = 0; my $line_count = 0; my $problem_count = 0; open FILE, "<$infilename" or die "could not open file $infilename: $!\n"; while () { $line_count = $line_count + 1; # print STDERR "[$mode] line $line_count\n"; if ($mode == 0) { if (/[:alpha:].*/) { $problem_count = ($problem_count + 1); print STDERR "[$mode] start of problem $_"; $problem_name = "$basename $problem_count: $_"; $mode = 1; } elsif (/([0-9]+) ([0-9]+)/) { $problem_count = ($problem_count + 1); print STDERR "[$mode] $1 orders, $2 products\n"; $problem_name = "$basename $problem_count\n"; $orders = $1; $current_order = 1; $products = $2; $mode = 2; } } elsif ($mode == 1) { if (/([0-9]+) ([0-9]+)/) { print STDERR "[$mode] $1 orders, $2 products\n"; $orders = $1; $current_order = 1; $products = $2; $mode = 2; } else { print STDERR "[$mode] ERROR (line $line_count): dimension not found\n"; $mode = 0; } } elsif ($mode == 2) { # print STDERR "[$mode] order $current_order is \"$_\"\n"; my $current_product = 1; while (/[:blank:]*(1|0)(.*)/) { if ($1 == "1") { # print STDERR "order $current_order includes product $current_product\n"; $includes{$current_order,$current_product} = 1; } else { # print STDERR "order $current_order does NOT include product $current_product\n"; $includes{$current_order,$current_product} = 0; } $current_product = ($current_product + 1); $_ = $2; } if ($current_product <= $products) { print STDERR "[$mode] ERROR (line $line_count): only ($current_product - 1) bits found in order $current_order description\n"; $mode = 0; } $current_order = ($current_order + 1); if ($current_order > $orders) { if (not (defined $opt_skip and ($problem_count <= $opt_skip))) { if (defined $opt_cp) { write_constraint_program(); } elsif (defined $opt_sat) { write_CNF(); } elsif (defined $opt_zinc) { write_zinc(); } elsif (defined $opt_cut) { write_cut(); } elsif (defined $opt_info) { write_info(); } else { write_problem(); } if (defined $opt_n) { if (defined $opt_skip) { if ($problem_count >= ($opt_skip + $opt_n)) { exit 0; } } elsif ($problem_count >= $opt_n) { exit 0; } } } $mode = 0; } } } sub write_problem { my $filename; my $problemname; my $problem_type = ""; my $problem_limits; my $problem_params = ""; my $is_strips = 1; my $max = $orders; if (defined $opt_bounded) { $max = $opt_bounded; } if (defined $opt_soft) { $problem_type = ($problem_type . "soft"); $is_strips = 0; } if (defined $opt_numeric) { if (defined $opt_simple) { $problem_type = ($problem_type . "simplenumeric"); } else { $problem_type = ($problem_type . "numeric"); } $is_strips = 0; } if (defined $opt_preferences) { $problem_type = ($problem_type . "preferences"); $is_strips = 0; if (defined $opt_derived) { $problem_type = ($problem_type . "derived"); } } if (defined $opt_constraints) { $problem_type = ($problem_type . "constraints"); $is_strips = 0; } if (defined $opt_time) { if (defined $opt_numeric) { $problem_type = "complex"; } else { $problem_type = ($problem_type . "time"); $is_strips = 0; } } if ($is_strips) { if (defined $opt_sequenced) { $problem_type = "sequencedstrips"; } else { $problem_type = "strips"; } } $problem_params = "_" unless (not defined $opt_range and not defined $opt_seed); if (defined $opt_range) { $problem_params = ($problem_params . "r$opt_range"); } if (defined $opt_seed) { $problem_params = ($problem_params . "s$opt_seed"); } if (defined $opt_fixed) { if (defined $opt_bounded) { $problem_limits = "fixed$opt_bounded"; } else { $problem_limits = "fixed"; } } elsif (defined $opt_bounded) { $problem_limits = "max$opt_bounded"; } # figure out filename if (defined $opt_ipc) { if (length($opt_ipc) < 2) { $filename = "p0$opt_ipc.pddl"; } else { $filename = "p$opt_ipc.pddl"; } $opt_ipc = ($opt_ipc + 1); } elsif (defined $problem_limits) { $filename = "os\_$problem_type\_$basename\_$problem_count\_$problem_limits$problem_params.pddl"; } else { $filename = "os\_$problem_type\_$basename\_$problem_count$problem_params.pddl"; } # figure out problem name if (defined $problem_limits) { $problemname = "os-$problem_type-$basename-$problem_count-$problem_limits"; } else { $problemname = "os-$problem_type-$basename-$problem_count"; } print STDERR "writing problem $problem_count to $filename...\n"; my $file_handle; open ($file_handle, ">:crlf", $filename); # preamble print $file_handle ";; problem $problem_name"; my $nec = ($orders * 2) + $products; print $file_handle ";; $orders orders, $products products (max open stacks = \#actions - $nec)\n"; print $file_handle "(define (problem $problemname)\n"; print $file_handle " (:domain openstacks-$problem_type)\n"; # object decls print $file_handle " (:objects"; unless (defined $opt_numeric or defined $opt_derived) { foreach my $i (0 .. $max) { print $file_handle " n$i"; }; print $file_handle " - count"; } foreach my $i (1 .. $orders) { print $file_handle " o$i"; }; print $file_handle " - order"; foreach my $i (1 .. $products) { print $file_handle " p$i"; }; print $file_handle " - product)\n"; # end :objects # init spec print $file_handle " (:init"; if (defined $opt_sequenced) { print $file_handle " (machine-available)"; } unless (defined $opt_numeric or defined $opt_derived) { foreach my $i (1 .. $max) { my $j = $i - 1; print $file_handle " (next-count n$j n$i)"; } if (defined $opt_preferences) { print $file_handle " (stacks-in-use n0)"; } else { if (defined $opt_fixed) { print $file_handle " (stacks-avail n$max)"; } else { print $file_handle " (stacks-avail n0)"; } } } foreach my $i (1 .. $orders) { print $file_handle " (waiting o$i)"; unless (defined $opt_constraints) { for my $j (1 .. $products) { if ($includes{$i,$j}) { print $file_handle " (includes o$i p$j)"; } } } } if (defined $opt_time) { my $r = 10; if (defined $opt_range) { $r = $opt_range; } foreach my $i (1 .. $products) { my $t = ((random() % $r) + 1) * $orders; print $file_handle " (= (make-time p$i) $t)"; } } if (defined $opt_numeric) { if (defined $opt_simple and not defined $opt_preferences) { print $file_handle " (= (stacks-avail) 0)"; } else { print $file_handle " (= (stacks-in-use) 0)"; } unless (defined $opt_simple) { print $file_handle " (= (max-in-use) 0)"; } } print $file_handle ")\n"; # end :init # goal spec print $file_handle " (:goal (and"; foreach my $i (1 .. $orders) { print $file_handle " (shipped o$i)"; } my $sum = 0; if (defined $opt_soft) { if (defined $opt_exponential) { for my $i (1 .. $orders) { my @p = order_product_list($i); my $v = 1; for my $n (0 .. $#p) { my $n1 = $n + 1; if ($n1 == 1) { print $file_handle " (preference d\-o$i\-n$n1 (delivered o$i p$p[0]))"; } else { print $file_handle " (preference d\-o$i\-n$n1 (and"; for my $j (0 .. $n) { print $file_handle " (delivered o$i p$p[$j])"; } print $file_handle "))"; } my $new_v = $v * 2; $sum = ($sum + ($new_v - $v)); $v = $new_v; } } } else { for my $i (1 .. $orders) { for my $j (1 .. $products) { if ($includes{$i,$j}) { print $file_handle " (preference d\-o$i\-p$j (delivered o$i p$j))"; $sum = ($sum + 1); } } } } } print $file_handle "))\n"; # end :goal if (defined $opt_soft) { print $file_handle " ;; max value = $sum\n"; } # constraint spec if (defined $opt_constraints or defined $opt_preferences) { print $file_handle " (:constraints (and"; if (defined $opt_preferences) { if (defined $opt_derived) { for my $i (1 .. $max) { print $file_handle " (preference max$i (always (not (orders-open-$i))))"; } } elsif (defined $opt_numeric) { for my $i (1 .. $orders) { print $file_handle " (preference max$i (always (< (stacks-in-use) $i)))"; } } else { for my $i (1 .. $max) { print $file_handle " (preference max$i (always (not (stacks-in-use n$i))))"; } } } if (defined $opt_constraints) { for my $i (1 .. $orders) { for my $j (1 .. $products) { if ($includes{$i,$j}) { print $file_handle " (sometime-before (made p$j) (started o$i))"; print $file_handle " (sometime-before (shipped o$i) (made p$j))"; } } } } print $file_handle "))\n"; # end :constraints } if (defined $opt_soft) { print $file_handle " (:metric maximize "; if (defined $opt_preferences) { print $file_handle "(- "; } if (defined $opt_exponential) { for my $i (1 .. $orders - 1) { my @p = order_product_list($i); my $v = 1; print $file_handle "(+ "; for my $n (0 .. $#p - 1) { my $n1 = $n + 1; my $new_v = 2 * $v; my $this_v = $new_v - $v; $v = $new_v; print $file_handle "(+ (* $this_v (- 1 (is-violated d\-o$i\-n$n1))) "; } my $n1 = $#p + 1; my $new_v = 2 * $v; my $this_v = $new_v - $v; print $file_handle "(* $this_v (- 1 (is-violated d\-o$i\-n$n1)))"; for my $j (0 .. $#p - 1) { print $file_handle ")"; } } # last order my @p = order_product_list($orders); my $v = 1; for my $n (0 .. $#p - 1) { my $n1 = $n + 1; my $new_v = 2 * $v; my $this_v = $new_v - $v; $v = $new_v; print $file_handle "(+ (* $this_v (- 1 (is-violated d\-o$orders\-n$n1))) "; } my $n1 = $#p + 1; my $new_v = 2 * $v; my $this_v = $new_v - $v; print $file_handle "(* $this_v (- 1 (is-violated d\-o$orders\-n$n1)))"; for my $j (0 .. $#p - 1) { print $file_handle ")"; } for my $i (1 .. $orders - 1) { print $file_handle ")"; } } else { for my $i (1 .. $orders - 1) { my @p = order_product_list($i); print $file_handle "(+ "; for my $j (0 .. $#p - 1) { print $file_handle "(+ (- 1 (is-violated d\-o$i\-p$p[$j])) "; } print $file_handle "(- 1 (is-violated d\-o$i\-p$p[$#p]))"; for my $j (0 .. $#p - 1) { print $file_handle ")"; } } # last order my @p = order_product_list($orders); for my $j (0 .. $#p - 1) { print $file_handle "(+ (- 1 (is-violated d\-o$orders\-p$p[$j]))"; } print $file_handle "(- 1 (is-violated d\-o$orders\-p$p[$#p]))"; for my $j (0 .. $#p - 1) { print $file_handle ")"; } for my $i (1 .. $orders - 1) { print $file_handle ")"; } } if (defined $opt_preferences) { for my $i (1 .. $max - 1) { if (defined $opt_weight) { print $file_handle "(+ (* $opt_weight (is-violated max$i))"; } else { print $file_handle "(+ (is-violated max$i)"; } } if (defined $opt_weight) { print $file_handle "(* $opt_weight (is-violated max$max))"; } else { print $file_handle "(is-violated max$max)"; } for my $i (1 .. $max - 1) { print $file_handle ")"; } print $file_handle ")"; } print $file_handle ")\n"; } elsif (defined $opt_preferences) { print $file_handle " (:metric minimize "; for my $i (1 .. $max - 1) { if (defined $opt_weight) { print $file_handle "(+ (* $opt_weight (is-violated max$i))"; } else { print $file_handle "(+ (is-violated max$i)"; } } if (defined $opt_weight) { print $file_handle "(* $opt_weight (is-violated max$max))"; } else { print $file_handle "(is-violated max$max)"; } for my $i (1 .. $max - 1) { print $file_handle ")"; } print $file_handle ")\n"; } elsif (defined $opt_numeric and not defined $opt_simple) { if (defined $opt_time) { if (defined $opt_weight) { print $file_handle " (:metric minimize (+ (* $opt_weight (max-in-use)) (total-time)))\n"; } else { print $file_handle " (:metric minimize (+ (max-in-use) (total-time)))\n"; } } else { print $file_handle " (:metric minimize (max-in-use))\n"; } } elsif (defined $opt_time) { print $file_handle " (:metric minimize (total-time))\n"; } print $file_handle ")\n"; # end (define (problem ...)) close $file_handle; } sub order_product_list { my $which_order = shift; my @l = (); for my $i (1 .. $products) { if ($includes{$which_order,$i}) { @l = (@l, $i); } } # print STDERR "order $which_order product list: @l (length = $#l)\n"; return @l; } sub count_products_in_order { my $which_order = shift; my $n = 0; for my $i (1 .. $products) { if ($includes{$which_order,$i}) { $n = ($n + 1); } } # print STDERR "order $which_order product list: @l (length = $#l)\n"; return $n; } sub write_constraint_program { my $filename; my $problem_limits; my $max = $orders; if (defined $opt_bounded) { $max = $opt_bounded; } if (defined $opt_bounded) { $problem_limits = "max$opt_bounded"; } if (defined $problem_limits) { $filename = "solve\_$basename\_$problem_count\_$problem_limits.ecl"; } else { $filename = "solve\_$basename\_$problem_count.ecl"; } print STDERR "writing problem $problem_count to $filename...\n"; my $file_handle; open ($file_handle, ">:crlf", $filename); # library import print $file_handle ":- lib(ic).\n\n"; # define the setup procedure print $file_handle "setup("; foreach my $i (1 .. $products) { if ($i > 1) { print $file_handle ","; } print $file_handle "P$i"; } print $file_handle ",NMAX) :-\n"; # basic constraints on Pi variables foreach my $i (1 .. $products) { print $file_handle "\tP$i :: 1 .. $products,\n"; } print $file_handle "\talldifferent(["; foreach my $i (1 .. $products) { if ($i > 1) { print $file_handle ","; } print $file_handle "P$i"; } print $file_handle "]),\n"; # define Fi variables foreach my $i (1 .. $orders) { my @p = order_product_list($i); print $file_handle "\tminlist(["; for my $j (0 .. $#p - 1) { print $file_handle "P$p[$j],"; } print $file_handle "P$p[$#p]],F$i),\n"; } # define Li variables foreach my $i (1 .. $orders) { my @p = order_product_list($i); print $file_handle "\tmaxlist(["; for my $j (0 .. $#p - 1) { print $file_handle "P$p[$j],"; } print $file_handle "P$p[$#p]],L$i),\n"; } # define Oij variables foreach my $i (1 .. $orders) { foreach my $j (1 .. $products) { print $file_handle "\tO$i\_$j \#= (F$i \#=< $j and L$i \#>= $j),\n"; } } # define Ni variables foreach my $i (1 .. $products) { print $file_handle "\tN$i \#= "; foreach my $j (1 .. $orders - 1) { print $file_handle "O$j\_$i +"; } print $file_handle "O$orders\_$i,\n"; } # constrain NMAX print $file_handle "\tmaxlist(["; foreach my $i (1 .. $products) { if ($i > 1) { print $file_handle ","; } print $file_handle "N$i"; } print $file_handle "],NMAX).\n\n"; # define a bounded solve procedure print $file_handle "solve_with_bound(B) :-\n"; print $file_handle "\tsetup("; foreach my $i (1 .. $products) { if ($i > 1) { print $file_handle ","; } print $file_handle "P$i"; } print $file_handle ",NMAX),\n"; print $file_handle "\tNMAX \#=< B,\n"; print $file_handle "\tlabeling(["; foreach my $i (1 .. $products) { if ($i > 1) { print $file_handle ","; } print $file_handle "P$i"; } print $file_handle ",NMAX]),\n"; print $file_handle "\tprintf(\"schedule: \%w, max \#open: \%u\%n\",[["; foreach my $i (1 .. $products) { if ($i > 1) { print $file_handle ","; } print $file_handle "P$i"; } print $file_handle "],NMAX]).\n"; # main call # print $file_handle ":- setup("; # foreach my $i (1 .. $products) { # if ($i > 1) { print $file_handle ","; } # print $file_handle "P$i"; # } # print $file_handle ",NMAX),\n"; # if (defined $opt_bounded) { # print $file_handle " NMAX \#=< $opt_bounded,\n"; # } # print $file_handle " labeling(["; # foreach my $i (1 .. $products) { # if ($i > 1) { print $file_handle ","; } # print $file_handle "P$i"; # } # print $file_handle ",NMAX]),\n"; # print $file_handle " printf(\"schedule: \%w, max \#open: \%u\%n\",[["; # foreach my $i (1 .. $products) { # if ($i > 1) { print $file_handle ","; } # print $file_handle "P$i"; # } # print $file_handle "],NMAX]).\n"; close $file_handle; } sub write_CNF { my $filename; my $problem_limits; my $max = $orders; if (defined $opt_bounded) { $max = $opt_bounded; } if (defined $opt_bounded) { $problem_limits = "max$opt_bounded"; } if (defined $problem_limits) { $filename = "test\_$basename\_$problem_count\_$problem_limits.cnf"; } else { $filename = "test\_$basename\_$problem_count.cnf"; } print STDERR "writing problem $problem_count to $filename...\n"; my $file_handle; open ($file_handle, ">:crlf", $filename); # comments before "p"-line seem to be acceptable to more solvers print $file_handle "c problem $basename\_$problem_count with bound $max\n"; my $n_points = ((2 * $orders) + $products); my $at_prec = ($n_points * $n_points); my $n_per_map = ($orders * $max); my $at_map = ($products * $n_per_map); my $cl_tc = ($n_points * ($n_points - 1) * ($n_points - 2)); my $cl_to = ($n_points * ($n_points - 1)); my $cl_ac = (($n_points * ($n_points - 1)) + $n_points); my $cl_ospec = $orders; for my $i (1 .. $orders) { my @p = order_product_list($i); $cl_ospec = ($cl_ospec + (2 * ($#p + 1))); } my $cl_map = ($products * $orders); my $cl_map_inj = ($products * (($orders * ($orders - 1)) / 2) * $max); my $cl_map_can = ($products * (($orders * ($orders - 1)) / 2) * (($max * ($max - 1)) / 2)); my $n_atoms = $at_prec + $at_map; my $n_clauses = $cl_tc + $cl_ac + $cl_ospec + $cl_map + $cl_map_inj + $cl_map_can; print $file_handle "p cnf $n_atoms $n_clauses\n"; if (defined $opt_comment) { print $file_handle "c transitivity of precedence ($cl_tc clauses):\n"; } for my $i (1 .. $n_points) { for my $j (1 .. $n_points) { for my $k (1 .. $n_points) { if ((not $i == $j) and (not $i == $k) and (not $j == $k)) { if (defined $opt_comment) { print $file_handle "c ($i < $j) & ($j < $k) -> ($i < $k)\n"; } my $i_prec_j = (($i - 1) * $n_points) + $j; my $j_prec_k = (($j - 1) * $n_points) + $k; my $i_prec_k = (($i - 1) * $n_points) + $k; print $file_handle "-$i_prec_j -$j_prec_k $i_prec_k 0\n"; } } } } if (defined $opt_comment) { print $file_handle "c acyclicity of precedence ($cl_ac clauses):\n"; } for my $i (1 .. $n_points) { for my $j (1 .. $n_points) { if (not $i == $j) { if (defined $opt_comment) { print $file_handle "c ($i < $j) -> !($j < $i)\n"; } my $i_prec_j = (($i - 1) * $n_points) + $j; my $j_prec_i = (($j - 1) * $n_points) + $i; print $file_handle "-$i_prec_j -$j_prec_i 0\n"; } } } if (defined $opt_comment) { print $file_handle "c irreflexivity of precedence:\n"; } for my $i (1 .. $n_points) { if (defined $opt_comment) { print $file_handle "c !($i < $i)\n"; } my $i_prec_i = (($i - 1) * $n_points) + $i; print $file_handle "-$i_prec_i 0\n"; } if (defined $opt_comment) { print $file_handle "c totality of precedence ($cl_to clauses):\n"; } for my $i (1 .. $n_points) { for my $j (1 .. $n_points) { if (not $i == $j) { if (defined $opt_comment) { print $file_handle "c ($i < $j) V ($j < $i)\n"; } my $i_prec_j = (($i - 1) * $n_points) + $j; my $j_prec_i = (($j - 1) * $n_points) + $i; print $file_handle "$i_prec_j $j_prec_i 0\n"; } } } if (defined $opt_comment) { print $file_handle "c order specification ($cl_ospec clauses):\n"; } for my $i (1 .. $orders) { my $start_i = $i; my $end_i = $orders + $i; my $start_prec_end = (($start_i - 1) * $n_points) + $end_i; if (defined $opt_comment) { print $file_handle "c start[$i] < end[$i] ($start_i < $end_i)\n"; } print $file_handle "$start_prec_end 0\n"; my @p = order_product_list($i); for my $j (0 .. $#p) { my $make_pj = ((2 * $orders) + $p[$j]); my $start_prec_make = (($start_i - 1) * $n_points) + $make_pj; my $make_prec_end = (($make_pj - 1) * $n_points) + $end_i; if (defined $opt_comment) { print $file_handle "c start[$i] < make[$p[$j]] ($start_i < $make_pj)\n"; } print $file_handle "$start_prec_make 0\n"; if (defined $opt_comment) { print $file_handle "c make[$p[$j]] < end[$i] ($make_pj < $end_i)\n"; } print $file_handle "$make_prec_end 0\n"; } } if (defined $opt_comment) { print $file_handle "c mapping ($cl_map clauses):\n"; } for my $i (1 .. $products) { my $make_i = ((2 * $orders) + $i); for my $j (1 .. $orders) { my $start_j = $j; my $end_j = $orders + $j; my $start_prec_make = (($start_j - 1) * $n_points) + $make_i; my $make_prec_end = (($make_i - 1) * $n_points) + $end_j; my $map_at_i = ($at_prec + (($i - 1) * $n_per_map)); if (defined $opt_comment) { my $first_map = ($map_at_i + (($j - 1) * $max) + 1); my $last_map = ($map_at_i + (($j - 1) * $max) + $max); print $file_handle "c start[$j] < make[$i] & make[$i] < end[$j] -> map[$j] to 1..$max at $i (($start_j < $make_i) & ($make_i < $end_j) -> ($first_map .. $last_map)\n"; } print $file_handle "-$start_prec_make -$make_prec_end"; for my $k (1 .. $max) { my $map_j_to_k = (($j - 1) * $max) + $k; my $map_j_to_k_at_i = ($map_at_i + $map_j_to_k); print $file_handle " $map_j_to_k_at_i"; } print $file_handle " 0\n"; } } if (defined $opt_comment) { print $file_handle "c injectivity of mapping ($cl_map_inj clauses):\n"; } for my $i (1 .. $products) { my $make_i = ((2 * $orders) + $i); for my $j (1 .. $orders) { for my $j2 (($j + 1) .. $orders) { for my $k (1 .. $max) { my $map_j_to_k = (($j - 1) * $max) + $k; my $map_j2_to_k = (($j2 - 1) * $max) + $k; my $map_at_i = ($at_prec + (($i - 1) * $n_per_map)); my $map_j_to_k_at_i = ($map_at_i + $map_j_to_k); my $map_j2_to_k_at_i = ($map_at_i + $map_j2_to_k); if (defined $opt_comment) { print $file_handle "c map[$j] = $k -> !map[$j2] = $k at $i\n"; } print $file_handle "-$map_j_to_k_at_i -$map_j2_to_k_at_i 0\n"; } } } } if (defined $opt_comment) { print $file_handle "c canonicity of mapping ($cl_map_can clauses):\n"; } for my $i (1 .. $products) { my $map_at_i = ($at_prec + (($i - 1) * $n_per_map)); for my $j (1 .. $orders) { for my $k (1 .. $max) { for my $j2 ($j + 1 .. $orders) { for my $k2 ($k + 1 .. $max) { my $map_j2_to_k = (($j2 - 1) * $max) + $k; my $map_j_to_k2 = (($j - 1) * $max) + $k2; my $map_j2_to_k_at_i = ($map_at_i + $map_j2_to_k); my $map_j_to_k2_at_i = ($map_at_i + $map_j_to_k2); if (defined $opt_comment) { print $file_handle "c map[$j2] = $k -> !map[$j] = $k2 at $i\n"; } print $file_handle "-$map_j2_to_k_at_i -$map_j_to_k2_at_i 0\n"; } } } } } close $file_handle; write_translation(); } sub write_translation { my $filename; my $problem_limits; my $max = $orders; if (defined $opt_bounded) { $max = $opt_bounded; } if (defined $opt_bounded) { $problem_limits = "max$opt_bounded"; } if (defined $problem_limits) { $filename = "restore\_$basename\_$problem_count\_$problem_limits.sed"; } else { $filename = "restore\_$basename\_$problem_count.sed"; } print STDERR "writing solution translator for $basename $problem_count to $filename...\n"; my $file_handle; open ($file_handle, ">:crlf", $filename); my $n_points = ((2 * $orders) + $products); my $at_prec = ($n_points * $n_points); my $n_per_map = ($orders * $max); my $at_map = ($products * $n_per_map); for my $i (1 .. $orders) { my $start_i = $i; my $end_i = $orders + $i; my $start_i_prec_end_i = (($start_i - 1) * $n_points) + $end_i; my $end_i_prec_start_i = (($end_i - 1) * $n_points) + $start_i; print $file_handle "s/^$start_i_prec_end_i\$/($start_i_prec_end_i) start[$i] < end[$i]/g\n"; print $file_handle "s/^-$start_i_prec_end_i\$/(-$start_i_prec_end_i) not start[$i] < end[$i]/g\n"; print $file_handle "s/^$end_i_prec_start_i\$/($end_i_prec_start_i) end[$i] < start[$i]/g\n"; print $file_handle "s/^-$end_i_prec_start_i\$/(-$end_i_prec_start_i) not end[$i] < start[$i]/g\n"; for my $j (1 .. $orders) { if (not $i == $j) { my $start_j = $j; my $end_j = $orders + $j; my $start_i_prec_end_j = (($start_i - 1) * $n_points) + $end_j; my $start_j_prec_end_i = (($start_j - 1) * $n_points) + $end_i; print $file_handle "s/^$start_i_prec_end_j\$/($start_i_prec_end_j) start[$i] < end[$j]/g\n"; print $file_handle "s/^-$start_i_prec_end_j\$/(-$start_i_prec_end_j) not start[$i] < end[$j]/g\n"; print $file_handle "s/^$start_j_prec_end_i\$/($start_j_prec_end_i) start[$j] < end[$i]/g\n"; print $file_handle "s/^-$start_j_prec_end_i\$/(-$start_j_prec_end_i) not start[$j] < end[$i]/g\n"; my $end_i_prec_start_j = (($end_i - 1) * $n_points) + $start_j; my $end_j_prec_start_i = (($end_j - 1) * $n_points) + $start_i; print $file_handle "s/^$end_i_prec_start_j\$/($end_i_prec_start_j) end[$i] < start[$j]/g\n"; print $file_handle "s/^-$end_i_prec_start_j\$/(-$end_i_prec_start_j) not end[$i] < start[$j]/g\n"; print $file_handle "s/^$end_j_prec_start_i\$/($end_j_prec_start_i) end[$j] < start[$i]/g\n"; print $file_handle "s/^-$end_j_prec_start_i\$/(-$end_j_prec_start_i) not end[$j] < start[$i]/g\n"; my $start_i_prec_start_j = (($start_i - 1) * $n_points) + $start_j; my $start_j_prec_start_i = (($start_j - 1) * $n_points) + $start_i; print $file_handle "s/^$start_i_prec_start_j\$/($start_i_prec_start_j) start[$i] < start[$j]/g\n"; print $file_handle "s/^-$start_i_prec_start_j\$/(-$start_i_prec_start_j) not start[$i] < start[$j]/g\n"; print $file_handle "s/^$start_j_prec_start_i\$/($start_j_prec_start_i) start[$j] < start[$i]/g\n"; print $file_handle "s/^-$start_j_prec_start_i\$/(-$start_j_prec_start_i) not start[$j] < start[$i]/g\n"; my $end_i_prec_end_j = (($end_i - 1) * $n_points) + $end_j; my $end_j_prec_end_i = (($end_j - 1) * $n_points) + $end_i; print $file_handle "s/^$end_i_prec_end_j\$/($end_i_prec_end_j) end[$i] < end[$j]/g\n"; print $file_handle "s/^-$end_i_prec_end_j\$/(-$end_i_prec_end_j) not end[$i] < end[$j]/g\n"; print $file_handle "s/^$end_j_prec_end_i\$/($end_j_prec_end_i) end[$j] < end[$i]/g\n"; print $file_handle "s/^-$end_j_prec_end_i\$/(-$end_j_prec_end_i) not end[$j] < end[$i]/g\n"; } } for my $j (1 .. $products) { my $make_j = ((2 * $orders) + $j); my $start_i_prec_make_j = (($start_i - 1) * $n_points) + $make_j; my $end_i_prec_make_j = (($end_i - 1) * $n_points) + $make_j; my $make_j_prec_start_i = (($make_j - 1) * $n_points) + $start_i; my $make_j_prec_end_i = (($make_j - 1) * $n_points) + $end_i; print $file_handle "s/^$start_i_prec_make_j\$/($start_i_prec_make_j) start[$i] < make[$j]/g\n"; print $file_handle "s/^-$start_i_prec_make_j\$/(-$start_i_prec_make_j) not start[$i] < make[$j]/g\n"; print $file_handle "s/^$end_i_prec_make_j\$/($end_i_prec_make_j) end[$i] < make[$j]/g\n"; print $file_handle "s/^-$end_i_prec_make_j\$/(-$end_i_prec_make_j) not end[$i] < make[$j]/g\n"; print $file_handle "s/^$make_j_prec_start_i\$/($make_j_prec_start_i) make[$j] < start[$i]/g\n"; print $file_handle "s/^-$make_j_prec_start_i\$/(-$make_j_prec_start_i) not make[$j] < start[$i]/g\n"; print $file_handle "s/^$make_j_prec_end_i\$/($make_j_prec_end_i) make[$j] < end[$i]/g\n"; print $file_handle "s/^-$make_j_prec_end_i\$/(-$make_j_prec_end_i) not make[$j] < end[$i]/g\n"; } } for my $i (1 .. $products) { my $make_i = ((2 * $orders) + $i); for my $j (1 .. $products) { my $make_j = ((2 * $orders) + $j); my $make_i_prec_make_j = (($make_i - 1) * $n_points) + $make_j; print $file_handle "s/^$make_i_prec_make_j\$/($make_i_prec_make_j) make[$i] < make[$j]/g\n"; print $file_handle "s/^-$make_i_prec_make_j\$/(-$make_i_prec_make_j) not make[$i] < make[$j]/g\n"; } } for my $i (1 .. $products) { my $map_at_i = ($at_prec + (($i - 1) * $n_per_map)); for my $j (1 .. $orders) { for my $k (1 .. $max) { my $map_j_to_k = (($j - 1) * $max) + $k; my $map_j_to_k_at_i = ($map_at_i + $map_j_to_k); print $file_handle "s/^$map_j_to_k_at_i\$/($map_j_to_k_at_i) map[$j] = $k at $i/g\n"; print $file_handle "s/^-$map_j_to_k_at_i\$/(-$map_j_to_k_at_i) not map[$j] = $k at $i/g\n"; } } } close $file_handle; } sub exponential_penalty_function { my $pos = shift; my $n = shift; my $sum = 0; my $v = 1; for my $k (1 .. $n) { if ($k >= $pos) { $sum = ($sum + $v); } $v = ($v * 2); } return $sum; } sub write_cut { my $filename; if (defined $opt_ipc) { if (length($opt_ipc) < 2) { $filename = "p0$opt_ipc.txt"; } else { $filename = "p$opt_ipc.txt"; } $opt_ipc = ($opt_ipc + 1); } else { $filename = "$basename\_$problem_count.txt"; } print STDERR "writing problem $problem_count to $filename...\n"; my $file_handle; open ($file_handle, ">:crlf", $filename); print $file_handle "$orders $products\n"; for my $i (1 .. $orders) { if (defined $opt_exponential) { my $p = 1; my $n = count_products_in_order($i); for my $j (1 .. $products) { if ($includes{$i,$j}) { my $c = exponential_penalty_function($p, $n); print $file_handle " $c"; $p = ($p + 1); } else { print $file_handle " 0"; } } } else { for my $j (1 .. $products) { if ($includes{$i,$j}) { print $file_handle " 1"; } else { print $file_handle " 0"; } } } print $file_handle "\n"; } if (defined $opt_time) { my $r = 10; if (defined $opt_range) { $r = $opt_range; } foreach my $i (1 .. $products) { my $t = ((random() % $r) + 1) * $orders; print $file_handle " $t"; } print $file_handle "\n"; } close $file_handle; } sub write_zinc { my $filename; $filename = "$basename\_$problem_count.zinc"; print STDERR "writing problem $problem_count to $filename...\n"; my $file_handle; open ($file_handle, ">:crlf", $filename); print $file_handle "include \"openstacks.zinc\";\n"; print $file_handle "nProducts = $products;\n"; print $file_handle "nOrders = $orders;\n"; print $file_handle "contains = ["; for my $i (1 .. $orders) { print $file_handle "["; for my $j (1 .. $products) { if ($includes{$i,$j}) { print $file_handle "true"; } else { print $file_handle "false"; } if ($j < $products) { print $file_handle ","; } } print $file_handle "]"; if ($i < $orders) { print $file_handle ","; } print $file_handle "\n"; } print $file_handle "];"; close $file_handle; } sub write_info { print STDOUT "problem $basename $problem_count:\n"; print STDOUT "\#orders = $orders\n"; print STDOUT "\#products = $products\n"; my $reduced_products = 0; for my $j (1 .. $products) { my $use_count = 0; for my $i (1 .. $orders) { if ($includes{$i,$j}) { $use_count = ($use_count + 1); } } if ($use_count > 0) { $reduced_products = ($reduced_products + 1); } else { print STDOUT "product \#$j is not required by any order\n"; } } print STDOUT "reduced \#products = $reduced_products\n"; }