RPP Generator

Kamil Veømiøovský, November, 2002

SICStus Prolog file generator.pl follows below. It can be also downloaded from here.

% ----------------------------------------------------------------------------
% 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.