packages feed

cpsa-4.4.1: src/perm.pl

% -*- mode: prolog -*-

%% Renumber strands in skeletons

%% Known to work in SWI-Prolog, but not with GNU Prolog.

%% Copyright (c) 2012 The MITRE Corporation
%%
%% This program is free software: you can redistribute it and/or
%% modify it under the terms of the BSD License as published by the
%% University of California.

:- module(perm, [cpsa_permute/3]).

:- use_module(cpsa).

%% PERMUTE STRANDS

%% A permutation of length n is represented as a list of natural
%% numbers that contains all the numbers less than n.

%% This program renumbers all the skeletons in a file that have the
%% same number of strands as is the length of the permutation.
%% Everything else is passed through unchanged.

%% For example, to swap the strands in skeletons with two strands in
%% in.txt and put the output into out.txt, type:
%%
%% perm: cpsa_permute([1,0], 'in.txt', 'out.txt').

%% This program does not check that the given permutation is in fact a
%% valid permutation, so be sure to check your output carefully.

cpsa_permute(Perm, InFile, OutFile) :-
    cpsa:cpsa(InFile, Cpsas),
    cpsa_permute_all(Perm, Cpsas, OutCpsas),
    cpsa:cpsas_to_sexprs(OutCpsas, Sexpr),
    open(OutFile, write, Stream),
    cpsa:cpsa_sexprs_pp(Stream, Sexpr),
    close(Stream).

cpsa_permute_all(_, [], []).
cpsa_permute_all(Perm, [Cpsa|Cpsas], [OutCpsa|OutCpsas]) :-
    cpsa_permute_skel(Perm, Cpsa, OutCpsa),
    cpsa_permute_all(Perm, Cpsas, OutCpsas).

cpsa_permute_skel(Perm, k(Prot, Decls, Strands, Precedes, Nons, Pens, Uniqs),
		  k(Prot, Decls, OutStrands, OutPrecedes, Nons, Pens, Uniqs)) :-
    perm_list(Perm, Strands, OutStrands),
    perm_precedes(Perm, Precedes, OutPrecedes),
    !.
% If above fails, simply copy the input to the output and don't fail.
cpsa_permute_skel(_, Cpsa, Cpsa).

%% Apply a permutation to a list.
perm_list([], _, []).
perm_list([Index|Indices], List, [Value|Rest]) :-
    nth0(Index, List, Value),
    perm_list(Indices, List, Rest).

%% Apply a permutation to a list of pairs of nodes.
perm_precedes(_, [], []).
perm_precedes(Perm, [(N0, N1)|Precedes], [(OutN0, OutN1)|OutPrecedes]) :-
    perm_node(Perm, N0, OutN0),
    perm_node(Perm, N1, OutN1),
    perm_precedes(Perm, Precedes, OutPrecedes).

perm_node(Perm, (S, I), (OutS, I)) :-
    index_of(Perm, S, OutS).

% Returns the index of the first occurence of Element in List
index_of(List, Element, Index) :-
    index_of(List, Element, 0, Index).
index_of([],_,_,_) :-
    print_message(error,'Element not found in list'),
    fail.
index_of([Element|_], Element, Curr, Curr) :- !.
index_of([_|List], Element, Curr, Index) :-
    Next is Curr + 1,
    index_of(List, Element, Next, Index).