% ----------------------------------------------------------------------------
% GENERATION OF RANDOM PLACEMENT PROBLEM DEFINITION FILE
% ----------------------------------------------------------------------------
% ----------------------------------------------------------------------------
% Loading of used modules
% ----------------------------------------------------------------------------
% load prolog libraries
:- use_module( library( random ) ),
use_module( library( lists ) ),
use_module( library( system ) ).
% ----------------------------------------------------------------------------
% Main predicate
% ----------------------------------------------------------------------------
generate :-
% initialize random number generator
rng_init,
% load parameters
write( 'Loading parameters ...\n'),
ensure_loaded( parameters ),
number_of_objects( NumberOfRectangles ),
area_width( AreaWidth ),
area_height( AreaHeight ),
object_sizes( sizes( Sizes ), probabilities( Probabilities ) ),
( my_sum_list( Probabilities, 1.0 ) ->
true
;
my_sum_list( Probabilities, Sum ),
format( 'Error: the sum of object sizes probabilities is not 1.0, \c
but ~4f.\n', [ Sum ] ), halt
),
lower_bounds( bounds( Bounds ), probabilities( BProbabilities ) ),
( my_sum_list( BProbabilities, 1.0 ) ->
true
;
my_sum_list( BProbabilities, Sum2 ),
format( 'Error: the sum of object lower bounds probabilities is not 1.0, \c
but ~4f.\n', [ Sum2 ] ), halt
),
( max_list( Bounds, Max ), Max >= 1 ->
write( 'Error: there cannot be lower bound greater or equal to 100 % \c
of area height.\n'), halt
;
true
),
generated_file_name( GeneratedFileName ),
Area is AreaHeight * AreaWidth,
write( 'done\n' ),
nl,
% open file
write( 'Generating ... \n'),
open( GeneratedFileName, write, GenFile, [ reposition( true ) ] ),
% make names
make_names( NumberOfRectangles, Names ),
% write header of the random placement definition file
write( GenFile,
'% ----------------------------------------------------------\n'),
write( GenFile,
'% RANDOM PLACEMENT PROBLEM DEFINITION FILE \n'),
write( GenFile,
'% ----------------------------------------------------------\n'),
write( GenFile,
'% Description:\n%\n'),
format( GenFile, '% Number of objects: ~d\n', [ NumberOfRectangles ] ),
format( GenFile, '% Area: ~d x ~d = ~d \n',
[ AreaWidth, AreaHeight, Area ] ),
write( GenFile, '% Total area of objects: ' ),
stream_position( GenFile, StreamPosition1 ),
write( GenFile, ' \n' ),
write( GenFile, '% Area filled up with objects: ' ),
stream_position( GenFile, StreamPosition2 ),
write( GenFile, ' \n' ),
write( GenFile, '% Average Y lower bound: ' ),
stream_position( GenFile, StreamPosition3 ),
write( GenFile, ' \n' ),
write( GenFile, '% object_sizes( \n'),
format( GenFile, '% sizes( ~p ),\n', [ Sizes ] ),
format( GenFile, '% probabilities( ~p )\n', [ Probabilities ] ),
write( GenFile, '% ).\n'),
write( GenFile, '% lower_bounds( \n'),
format( GenFile, '% bounds( ~p ),\n', [ Bounds ] ),
format( GenFile, '% probabilities( ~p )\n', [ BProbabilities ] ),
write( GenFile, '% ).\n'),
write( GenFile,
'% ----------------------------------------------------------\n'),
nl( GenFile ),
% generate
bb_put( area, 0 ),
bb_put( sumY, 0 ),
write( GenFile, 'objects([\n' ),
foreach( Names, compatible, [ AreaWidth, AreaHeight, _,
Sizes, Probabilities, Bounds,
BProbabilities, GenFile ] ),
write( GenFile, '\n] ).\n' ),
bb_get( area, OArea ),
bb_get( sumY, SumY ),
Percent is ( OArea / Area ) * 100,
AverageLowerBound is SumY / NumberOfRectangles,
AveragePercent is ( AverageLowerBound / AreaHeight ) * 100,
set_stream_position( GenFile, StreamPosition1 ),
format( GenFile, '~d', [ OArea ] ),
set_stream_position( GenFile, StreamPosition2 ),
format( GenFile, '~2f %\n%', [ Percent ] ),
set_stream_position( GenFile, StreamPosition3 ),
format( GenFile, '~2f % of Area height\n%',
[ AveragePercent ] ),
close( GenFile ),
write( 'done.\n\n' ),
format( 'Area filled up with objects: ~2f %\n', [ Percent ] ),
format( 'Average lower bound: ~2f (~2f % of Area height) \n',
[ AverageLowerBound, AveragePercent ] ).
% ----------------------------------------------------------------------------
% Auxiliary predicates
% ----------------------------------------------------------------------------
% initialize random number generator
rng_init :-
now(Now),
G1 is (Now mod 30260) + 1,
G2 is 30261 - G1,
G3 is (((Now mod 100)*40000) mod 30200) + 1,
setrand(rand(G1, G2, G3)).
% count the sum of all elements of the list (the built in predicate
% doesn't work correctly
my_sum_list([], 0).
my_sum_list([X|Xs], M):-
my_sum_list( Xs, M0 ), M is M0 + X.
% for each element of the list call Goal(Element, Params)
foreach( [], _, _ ).
foreach( [X|Xs], Goal, Params ) :-
Call =.. [ Goal, X, Params ],
call( Call ),
foreach( Xs, Goal, Params ).
% for each {(X, Y)| X in From1..To1, Y in From2..To2} call Goal(X, Y, Params)
call_pairs( From1, To1, From2, To2, Goal, Params ) :-
call_pairs( From1, To1, From2, To2, From2, Goal, Params ).
call_pairs( To1, To1, _, To2, Cur, _, _ ) :-
Cur > To2,
!.
call_pairs( From1, To1, From2, To2, Cur, Goal, Params ) :-
Cur > To2,
!,
Pom is From1 + 1,
call_pairs( Pom, To1, From2, To2, From2, Goal, Params ).
call_pairs( From1, To1, From2, To2, Cur2, Goal, Params ) :-
Call =.. [ Goal, From1, Cur2, Params ],
call( Call ),
Pom is Cur2 + 1,
call_pairs( From1, To1, From2, To2, Pom, Goal, Params ).
% number_to_char(3, '3')
number_to_char( X, Xchar ) :-
number_codes(X, Temp), atom_codes(Xchar, Temp).
% choose_random chooses randomly element from the list, each element
% has its probability of choice, sum of the probabilities MUST be 1.0
% choose_random( +List, +Probabilities, -Element )
choose_random( [X|Xs], [P|Ps], Element ) :-
random( Number ),
%format( 'Random number: ~f', [ Number ] ),
( Number < P ->
Element = X
;
choose_random( Xs, Ps, P, Number, Element )
).
choose_random( [X|Xs], [P|Ps], Base, Number, Element ) :-
Probability is Base + P,
( Number < Probability ->
Element = X
;
choose_random( Xs, Ps, Probability, Number, Element )
).
% in_range( +Number, +Ranges, +List, -Element )
% find range among Ranges in which Number is and choose corresponding
% Element from List
% e.g. in_range( 3, [1-2, 3-5, 6-7], [a, b, c], b )
in_range( _, [], [], [] ).
in_range( X, [Min-Max|Ranges], [L|Ls], E ) :-
( X >= Min, X =< Max ->
E = L
;
in_range( X, Ranges, Ls, E )
).
% ----------------------------------------------------------------------------
% Domain generation predicates
% ----------------------------------------------------------------------------
compatible( X, [ AreaWidth, AreaHeight, IsFirst,
Sizes, Probabilities,
Bounds, BProbabilities, GenFile ] ) :-
choose_random( Sizes, Probabilities, [ Width, Height ] ),
( nonvar( IsFirst ) ->
write(GenFile, ',\n')
;
IsFirst = not
),
write(GenFile, ' object(\n'),
format( GenFile, ' name( ~p ),\n', [ X ] ),
format( GenFile, ' size( [ ~d, ~d ] ),\n', [ Width, Height ] ),
write( GenFile, ' valid_positions( [ '),
write(X), nl,
bb_get( area, Area0 ),
Area is Width * Height + Area0,
bb_put( area, Area ),
T1 is AreaWidth - Width,
T2 is AreaHeight - Height,
choose_random( Bounds, BProbabilities, Bound ),
Ymin is integer(Bound*AreaHeight),
bb_get( sumY, SumY0 ),
SumY is SumY0 + Ymin,
bb_put( sumY, SumY ),
format(GenFile, '~p, ~p', [ 0-T1, Ymin-T2 ] ),
write( GenFile, ' ] )\n' ),
write( GenFile, ' )' ).
% ----------------------------------------------------------------------------
% Rectangles names generation
% ----------------------------------------------------------------------------
make_names(N, Names ) :-
make_names( 1, N, Names ).
make_names( N, N, [ Name ] ) :-
number_to_char( N, Nchar ),
atom_concat( 'rect', Nchar, Name ),
!.
make_names( M, N, [ Name | Names ] ) :-
number_to_char( M, Mchar ),
atom_concat( 'rect', Mchar, Name ),
M2 is M + 1,
make_names( M2, N, Names ).
% ----------------------------------------------------------------------------
% Generator initiation
% ----------------------------------------------------------------------------
:- generate, halt.