Correcção do teste

Exame - 22 de Julho de 1999

OC98-99 (testes)


Condições gerais da prova

Índice


Questões

  1. Uma das formas de representar uma matriz usando Erlang, consiste em especificar um tuplo contendo quatro valores: Nº de colunas, Nº de linhas, Valor por defeito e Lista de valores da matriz. Cada elemento da lista consiste num tuplo de três elementos que especificam respectivamente a linha, coluna e o próprio valor. Qualquer posição não especificada na lista considera-se ter o valor por defeito.
  2. Ex.:

    5 -1 -1
    -1 10 -1
    -1 -1 15
    { 3, 3, -1, [ {0, 0, 5}, {1, 1, 10}, {2, 2, 15}] }

    Implemente um módulo Erlang denominado matrix com as seguintes funções de interface:

  1. create/3: Retorna um tuplo correspondente a uma matriz. Os dois primeiros argumentos são as dimensões da matriz e o terceiro é o valor da matriz por defeito. A lista de elementos fica vazia;
  2. set/4: Insere um valor na matriz. O primeiro parâmetro corresponde á matriz, os dois seguintes representam a posição na matriz, e o terceiro é o próprio valor. Se a posição especificada for inválida, um erro é retornado;
  3. get/3: Retorna um valor da matriz. O primeiro parâmetro corresponde á matriz, os dois seguintes representam a posição do valor na matriz. Se a posição for inválida, é retornado um erro;
  4. redim/3: Redimensiona a matriz. O primeiro parâmetro corresponde à matriz, os dois seguintes correspondem às novas dimensões da matriz. A nova dimensão tanto pode ser maior como menor que a anterior.

Resposta:

-module(matrix).

-export([create/3, set/4, get/3, redim/3]).

create( Dim_X, Dim_Y, Val_def) ->
    { Dim_X, Dim_Y, Val_def, [] }.

set( { Dim_X, Dim_Y, Val_def, L }, X, Y, Val ) when
	X < Dim_X, X >= 0, Y < Dim_Y, Y >= 0, Val =/= Val_def ->
    LN = [{X, Y, Val} | [ E || E <- L, element(1, E) =/= X, element(2, E) =/= Y] ],
    { Dim_X, Dim_Y, Val_def, LN };
set( { Dim_X, Dim_Y, Val_def, L }, X, Y, Val ) when
	X < Dim_X, X >= 0, Y < Dim_Y, Y >= 0 ->
    LN = [ E || E <- L, element(1, E) =/= X, element(2, E) =/= Y ],
    { Dim_X, Dim_Y, Val_def, LN };
set( _, _, _, _ ) ->
    { error, fora_de_limites }.

get( {Dim_X, Dim_Y, Val_def, L }, X, Y ) when
	X < Dim_X, X >= 0, Y < Dim_Y, Y >= 0 ->
    case [ E || E <- L, element(1, E) == X, element(2, E) == Y ] of
        [] -> Val_def;
        [ {_, _, Val} ] -> Val
    end;
get( _, _, _ ) ->
    { error, fora_de_limites }.

redim( { Dim_X, Dim_Y, Val_def, L }, X, Y ) when
	X >= Dim_X, Y >= Dim_Y ->
    { X, Y, Val_def, L };
redim( { Dim_X, Dim_Y, Val_def, L }, NewDim_X, NewDim_Y ) ->
    { NewDim_X, NewDim_Y, Val_def, [ E || E <- L, element(1, E) < NewDim_X, element(2, E) < NewDim_Y ] }.
Índice
  1. Faça um sistema que simule a ignição de um motor normal de um carro. A função principal deve ser chamada da seguinte forma:

    motor:motor(N_cilindros,N_ciclos,Atraso_cilindros)

    O processo motor deve criar um processo por cilindro. Depois dos processos serem criados, o processo principal envia uma mensagem de ignição ao primeiro cilindro que tem a obrigação de o propagar ao seguinte, o que acontece passado um intervalo de tempo dado por Atraso_cilindros em milisegundos. A ignição de todos os cilindros repete-se durante N_ciclos. O último cilindro devolve ao motor a mensagem ignição. Se essa devolução demorar mais do que 10*Atraso_cilindros*N_cilindros, a função deve terminar devolvendo o tuplo {erro,timeout}.

Resposta:

-module(motor).

-export([motor/3, cilindro/2]).

motor(N_cilindros, N_ciclos, Atraso_cilindros) ->
    Primeiro_cilindro = create_cilindros( N_cilindros, Atraso_cilindros ),
    processo_ignicao( Primeiro_cilindro, N_cilindros, N_ciclos, Atraso_cilindros ),
    Primeiro_cilindro ! kill,
    fim.

processo_ignicao( _, _, 0, _ ) -> fim;
processo_ignicao( Primeiro_cilindro, N_cilindros, N_ciclos, Atraso_cilindros ) ->
    Primeiro_cilindro ! ignicao,
    receive
        ignicao ->
            io:format("ignicao~n"),
            processo_ignicao( Primeiro_cilindro, N_cilindros, N_ciclos - 1, Atraso_cilindros )
    after 10 * Atraso_cilindros * N_cilindros ->
        { erro, timeout }
    end.

create_cilindros( 0, _ ) -> self();
create_cilindros( N_cilindros, Atraso_cilindros ) ->
    Pid_seguinte = create_cilindros( N_cilindros - 1, Atraso_cilindros ),
    spawn(?MODULE, cilindro, [Pid_seguinte, Atraso_cilindros] ).

cilindro( Pid_seguinte, Atraso_cilindros ) ->
    receive
        ignicao ->
            io:format("ignicao~n"),
            receive
                after Atraso_cilindros ->
                    Pid_seguinte ! ignicao,
                    cilindro( Pid_seguinte, Atraso_cilindros )
            end;
        kill ->
            Pid_seguinte ! kill
    end.
Índice 
  1. Considere a seguinte fórmula:

22-07-99(formula).gif (2004 bytes)

Implemente um sistema em forma de linha, composto por várias entidades, responsáveis pela execução da fórmula (para todos os elementos da matriz):

22-07-99(sistema).gif (4937 bytes)

Resposta:

% nao era exigida tanta promenorizacao
-module(formula).

-export([start/2, formula/1, pede_dados/1, divisao/1, subtracao/1, soma/1]).

-define(FORMULA, formula).

start( Node, Matrix ) ->
	spawn(Node, ?MODULE, formula, [Matrix]),
	executando.

formula( {X, Y, Val_def} ) ->
	register( ?FORMULA, self() ),
	process_flag(trap_exit, true ),
	Lista_Pid = cria_processos(),
	Matriz = matrix:create( X, Y, Val_def ),
	loop( Lista_Pid, Matriz ).

cria_processos( ) ->
	Soma = spawn_link(?MODULE, soma, [0] ),
	Subtracao = spawn_link(?MODULE, subtracao, [Soma] ),
	Divisao = spawn_link(?MODULE, divisao, [Subtracao] ),
	Pede_dados = spawn_link(?MODULE, pede_dados, [Divisao] ),
	[ {soma, Soma}, {subtracao, Subtracao}, {divisao, Divisao}, {pede_dados, Pede_dados} ].

recria_processos( Lista_Pid ) ->
	mata_processos( Lista_Pid ),
	cria_processos( ).

mata_processos( [] ) -> ok;
mata_processos( [ {Nome, Pid } | Lista_Pid ] ) ->
	exit(Pid, msg_morre),
	mata_processos( Lista_Pid ).

loop( Lista_Pid, Matriz ) ->
	receive
		{ 'EXIT', Pid, normal } ->
			loop( Lista_Pid, Matriz );
		{ 'EXIT', Pid, Razao } ->
			case Razao of
				fora_de_limites ->
					io:format("Erro nos dados.~n"),
					exit(erro_nos_dados);
				divisao_por_zero ->
					io:format("Divisao por zero.~n"),
					exit(divisao_por_zero);
				Else ->
					Lista_Pid_Nova = recria_processos( Lista_Pid ),
					loop( Lista_Pid_Nova, Matriz )
			end;
		{ msg_get_limits, Pid } ->
			{ X, Y } = matrix:get_limits( Matriz ),
			Pid ! { msg_limits, X, Y },
			loop( Lista_Pid, Matriz );
		{ msg_get_dados, Pid, X, Y } ->
			case matrix:get( Matriz, X, Y ) of
				{ error, fora_de_limites } ->
					Pid ! { msg_dados, fora_de_limites };
				Valor ->
					Pid ! { msg_dados, Valor }
			end,
			loop( Lista_Pid, Matriz );
		Resultado when number(Resultado) ->
			io:format("Resultado: ~w~n", [Resultado])
	end.

pede_dados( Pid_seguinte ) ->
	?FORMULA ! { msg_get_limits, self() },
	receive
		{ msg_limits, X, Y } ->
			loop_pede_dados( Pid_seguinte, X , Y, 0, 0 ),
			fim_pede_dados;
		Else ->
			exit( Else )
	end.

loop_pede_dados( Pid_seguinte, Xtotal, Ytotal, _, Ytotal ) ->
	Pid_seguinte ! msg_fim,
	fim_pede_dados;

loop_pede_dados( Pid_seguinte, Xtotal, Ytotal, Xtotal, Y ) ->
	loop_pede_dados( Pid_seguinte, Xtotal, Ytotal, 0, Y + 1 );

loop_pede_dados( Pid_seguinte, Xtotal, Ytotal, X, Y ) ->
	?FORMULA ! { msg_get_dados, self(), X, Y },
	receive
		msg_morre ->
			morre_pede_dados;

		{ msg_dados, fora_de_limites } ->
			exit( fora_de_limites );

		{ msg_dados, Valor_X } ->
			Pid_seguinte ! { msg_dados, Valor_X },
			loop_pede_dados( Pid_seguinte, Xtotal, Ytotal, X + 1 , Y )
	end.

soma( Resultado ) ->
	receive
		msg_fim ->
			?FORMULA ! Resultado,
			fim_soma;
		msg_morre ->
			morre_soma;
		{ msg_dados, Valor } ->
			soma( Resultado + Valor )
	end.

subtracao( Pid_seguinte ) ->
	receive
		msg_fim ->
			Pid_seguinte ! msg_fim,
			fim_subtracao;
		msg_morre ->
			morre_subtracao;
		{ msg_dados, Valor_X, Valor_A } ->
			Pid_seguinte ! { msg_dados, Valor_X - Valor_A },
			subtracao( Pid_seguinte )
	end.

divisao( Pid_seguinte ) ->
	receive
		msg_fim ->
			Pid_seguinte ! msg_fim,
			fim_divisao;
		msg_morre ->
			morre_divisao;
		{ msg_dados, Valor_X } ->
			case Valor_X of
				0 ->
					exit( divisao_por_zero );
				Else ->
					Pid_seguinte ! { msg_dados, Valor_X, 2 / Valor_X },
					divisao( Pid_seguinte )
			end
	end.
Índice

Última actualização: 14-03-2000

OC98-99 (testes)