function [tikz_link] = Minimal_Trellis_Arbitrary_Codes(code,range1,decoding,pathmetricswitch,cwswitch,inue_js_animationNumberOfFrames, filename)

  % input generatormatrix
  switch(code)
  case "ecc" % ECC example
  code_string = "ECC example";
    generatormatrix =  [1 1 1 0 0 0 0;
    0 1 1 1 1 0 0;      
    0 0 1 0 1 1 0;
    0 0 0 1 1 1 1]; ;
    
   case "decc" % Simplex Code
   code_string = "Simplex Code";
    generatormatrix = [0 0 0 1 1 1 1;
    0 1 1 0 0 1 1;      
    1 0 1 0 1 0 1]; 
    
  case "spc" % single parity check code
  code_string = "single parity check code";
    generatormatrix =  [1 0 0 0 0 0 1;
    0 1 0 0 0 0 1;      
    0 0 1 0 0 0 1;
    0 0 0 1 0 0 1;
    0 0 0 0 1 0 1;
    0 0 0 0 0 1 1]; 
    
  case "spcd" % single parity check code
  code_string = "repetition code";
    generatormatrix =  [1 1 1 1 1 1 1]; 
       
  case "hc" % 15,11 Hamming Code
  code_string = "15,11 Hamming Code";
    generatormatrix =  [1 0 0 0 0 0 0 0 0 0 0 0 0 1 1;
    0 1 0 0 0 0 0 0 0 0 0 0 1 0 1;      
    0 0 1 0 0 0 0 0 0 0 0 0 1 1 0;
    0 0 0 1 0 0 0 0 0 0 0 0 1 1 1;  
    0 0 0 0 1 0 0 0 0 0 0 1 0 0 1;
    0 0 0 0 0 1 0 0 0 0 0 1 0 1 0;
    0 0 0 0 0 0 1 0 0 0 0 1 0 1 1;
    0 0 0 0 0 0 0 1 0 0 0 1 1 0 0;
    0 0 0 0 0 0 0 0 1 0 0 1 1 0 1;
    0 0 0 0 0 0 0 0 0 1 0 1 1 1 0;
    0 0 0 0 0 0 0 0 0 0 1 1 1 1 1];
   
  case "dhc" % 15,11 Hamming Code
  code_string = "15,11 Hamming Code";
    generatormatrix = [0 0 0 0 0 0 0 1 1 1 1 1 1 1 1; 
    0 0 0 1 1 1 1 0 0 0 0 1 1 1 1;
    0 1 1 0 0 1 1 0 0 1 1 0 0 1 1;
    1 0 1 0 1 0 1 0 1 0 1 0 1 0 1];
    
  case "rma" % RM(1,3)
  code_string = "RM(1,3)";
    generatormatrix =  [1 1 1 1 0 0 0 0;
    0 1 0 1 1 0 1 0;
    0 0 1 1 1 1 0 0;
    0 0 0 0 1 1 1 1];

    case "rmb" % RM(1,4)
  code_string = "RM(1,4)";
    generatormatrix =  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
                        0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1;
                        0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1;
                        0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1;
                        0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1];
                 
  case "rmc" % RM(1,5)
  code_string = "RM(1,5)";
    generatormatrix =  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1;
    0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1;
    0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1;
    0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1;
    0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1;
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1];
 
endswitch

% input amount of bit errors in case of decoding
switch (decoding)
  case 1
if range1 <= size(generatormatrix,2)
number_of_errors_seq = range1;
elseif range1 > size(generatormatrix,2)
number_of_errors_seq = size(generatormatrix,2)
end
case 0

endswitch

% general trellis structures
% conversions 
[trellis_oriented_matrix,index_matrix] = trellis_oriented_form(generatormatrix);
compression = find_compression(trellis_oriented_matrix,index_matrix);
[starts, ends, bits] = reduced_compressed_trellis_product(trellis_oriented_matrix, compression, index_matrix); % "bits": edge-output of "starts"-"ends"-transitions
% starts of pathsegments
starts_str = starts;
starts_str(:,:) = "x";
starts_int = starts;
starts_int(:,:) = " ";
% ends of pathsegments
ends_str = ends;
ends_str(:,:) = "x";
ends_int = ends;
ends_int(:,:) = " ";
% bits of pathsegments
bits_str = bits;
bits_str(:,:) = "x";
% trellis dimensions
codewords_amount = 2^size(trellis_oriented_matrix,1); 
segments_amount = length(compression);
time_instances = segments_amount+1;
max_row = 0;

% compress starts, ends, bits for trellis and TikZ 
for j = 1:length(compression)
  for i = 1:codewords_amount
    start_temp = (starts{i,j});
    end_temp = (ends{i,j});
    bit_temp = (bits{i,j});
    pathsegment = 0;
    for k = 1:codewords_amount
      if strcmp(starts_str{k,j},start_temp) == 1 && strcmp(ends_str{k,j},end_temp) == 1
        pathsegment = pathsegment+1;
      end
    end
    if pathsegment == 0
      starts_str{i,j} = start_temp;
      ends_str{i,j} = end_temp;
      bits_str{i,j} = bit_temp;
    elseif pathsegment > 0
      starts_str{i,j} = " ";
      ends_str{i,j} = " ";
      bits_str{i,j} = " ";
    end
  end
end

for j = 1:(length(compression)+1)
  states_lookup = cell(codewords_amount,2);
  state_count = 1;
  for i = 1:codewords_amount
    start_found = 0;
    end_found = 0;
    if j == 1
      start_temp = (starts_str{i,j});
      if strcmp(start_temp," ") == 1
        starts_int{i,j} = " ";
      else
        for k = 1:codewords_amount
          if strcmp(states_lookup{k,1},start_temp) == 1
            start_integer = states_lookup{k,2}; 
            start_found = start_found+1;
          end
        end
        if start_found == 0
          states_lookup(state_count,1) = start_temp;
          states_lookup(state_count,2) = state_count;
          start_integer = state_count;
          state_count = state_count+1;
        end
        starts_int{i,j} = start_integer;
      end
    elseif j == (length(compression)+1)
      end_temp = (ends_str{i,j-1});
      if strcmp(end_temp," ") == 1
        ends_int{i,j-1} = " ";
      else
        for k = 1:codewords_amount
          if strcmp(states_lookup{k,1},end_temp) == 1
            end_integer = states_lookup{k,2}; 
            end_found = end_found+1;
          end
        end
        if end_found == 0
          states_lookup(state_count,1) = end_temp;
          states_lookup(state_count,2) = state_count;
          end_integer = state_count;
          state_count = state_count+1;
        end
        ends_int{i,j-1} = end_integer;
      end
    else
      start_temp = (starts_str{i,j});
      end_temp = (ends_str{i,j-1});
      if strcmp(start_temp," ") == 1
        starts_int{i,j} = " ";
      else
        for k = 1:codewords_amount
          if strcmp(states_lookup{k,1},start_temp) == 1
            start_integer = states_lookup{k,2}; 
            start_found = start_found+1;
          end
        end
        if start_found == 0
          states_lookup(state_count,1) = start_temp;
          states_lookup(state_count,2) = state_count;
          start_integer = state_count;
          state_count = state_count+1;
        end
        starts_int{i,j} = start_integer;
      end
      if strcmp(end_temp," ") == 1
        ends_int{i,j} = " ";
      else
        for k = 1:codewords_amount
          if strcmp(states_lookup{k,1},end_temp) == 1
            end_integer = states_lookup{k,2}; 
            end_found = end_found+1;
          end
        end
        if end_found == 0
          states_lookup(state_count,1) = end_temp;
          states_lookup(state_count,2) = state_count;
          end_integer = state_count;
          state_count = state_count+1;
        end
        ends_int{i,j-1} = end_integer;
        if max_row < ends_int{i,j-1}
          max_row = ends_int{i,j-1};
        end
      end
    end
  end
end
states_amount = max_row;

if decoding == 0
  else % code only executed if decoding is wanted
% decoding structures
% lifespan of pathsegments
lifespan = 1000*ones(codewords_amount,1,segments_amount);
% possible entrys of lifespan:
deadtransition = 0;
livingtransition = 1;
stillalive = 8888;
stillborn = 9999;
nonexistent = 1000;
  % structures for trellis decoding
path_metric_array = 1000*ones(codewords_amount, time_instances);
path_metric_array(1,1) = 0;
edge_metric = 0;
  % bulid received_vector with random bit errors
  for j = 1:size(generatormatrix,1)
    message(j,1) = randi([0,1]);
  end
  codeword = rem(message'*generatormatrix,2);
  received_vector = codeword;
  errorpositions = zeros(number_of_errors_seq,1);
  possible_errorpositions = zeros(length(codeword));
  for m = 1:length(codeword)
    possible_errorpositions(m) = m;
  end
  for n = 1:number_of_errors_seq
    while errorpositions(n) == 0
      error_index = randi([1,length(codeword)]);
      if possible_errorpositions(error_index) != 0
        errorpositions(n) = possible_errorpositions(error_index);
        possible_errorpositions(error_index) = 0;
      end
    end
  end
  errorpositions=sort(errorpositions);
  error_count = 1;
    for j=1:length(codeword)
      if error_count <= range1
      if j == errorpositions(error_count) 
        received_vector(errorpositions(error_count)) = abs(codeword(errorpositions(error_count))-1);
        error_count = error_count+1;
      end
      end
    end
% group received_vector according to compression
k = 1;
recstr = "";
for i= 1:length(compression)
  for j = 1:compression(i)
    recstr = strcat(recstr,num2str(received_vector(k)));
    k = k+1;
  end
  received{i,1} = recstr;
  recstr = "";
end

% exits of states per time instance
exits = zeros(states_amount,2,segments_amount); % Columns: 1:exit_sum 2:dead_exits_count; 

% viterbi algorithm
for j = 1:segments_amount
  for i = 1:codewords_amount
    if strcmp((bits_str{i,j})," ") == 0 % if bit-string exists check if bit error occurs
      arrival_state = ends_int{i,j};
      origin_state = starts_int{i,j};
      string_equivalence = strcmp((bits_str{i,j}),received{j,1});
      if string_equivalence == 0 % if bit error occurs add edge_metric
        weight_aggregated = 0;
        for m = 1:compression(j)
          if ((bits_str{i,j})(m)) ~= ((received{j,1})(m))
            weight_aggregated = weight_aggregated+1;
          end
        end
        edge_metric = path_metric_array(starts_int{i,j},j)+weight_aggregated;
      elseif string_equivalence == 1
        edge_metric = path_metric_array(starts_int{i,j},j);
      end
      % save calcualted transition as first, further or only survivor or as dead        
      if (path_metric_array(arrival_state,j+1) > edge_metric) && (path_metric_array(arrival_state,j+1) == 1000) % 1st alive transition to state arrival_state found
        path_metric_array(arrival_state,j+1) = edge_metric;
        exits(origin_state,1,j) = exits(origin_state,1,j)+1;
        lifespan(i,1,j) = stillalive;
      elseif path_metric_array(arrival_state,j+1) == edge_metric % further alive transition to state arrival_state found
        exits(origin_state,1,j) = exits(origin_state,1,j)+1;
        lifespan(i,1,j) = stillalive; 
      elseif (path_metric_array(arrival_state,j+1) > edge_metric) && (path_metric_array(arrival_state,j+1) < 1000) % new better alive transition found, other transition dies
        path_metric_array(arrival_state,j+1) = edge_metric;
        exits(origin_state,1,j) = exits(origin_state,1,j)+1;
        lifespan(i,1,j) = stillalive;
        for m = 1:i-1
          if (ends_int{m,j} == arrival_state) && (lifespan(m,1,j) == stillalive)
            exits(starts_int{m,j},2,j) = exits(starts_int{m,j},2,j)+1;
            lifespan(m,1,j) = stillborn;
          end
        end
      elseif (path_metric_array(arrival_state,j+1) < edge_metric) && (path_metric_array(arrival_state,j+1) < 1000) %&& (path_metric_array(i,j) < 1000) % dead transition found
        exits(origin_state,1,j) = exits(origin_state,1,j)+1;
        exits(origin_state,2,j) = exits(origin_state,2,j)+1;
        lifespan(i,1,j) = stillborn;
      end       
    end
    edge_metric = 0;
  end
  if j >= 2
    for m = j:-1:2
      for l = 1:states_amount
        % amout of exitsum equals amount of dead exits
        if (exits(l,1,m) == exits(l,2,m)) && (exits(l,1,m)>0)
          for n = 1:codewords_amount
            if ends_int{n,m-1} == l && lifespan(n,1,m-1) == stillalive;          
              exits(starts_int{n,m-1},2,m-1) = exits(starts_int{n,m-1},2,m-1)+1; % adapt dead exits of state with depending dead transition
              lifespan(n,1,m-1) = j;
            end
          end
          exits(l,1,m) = 0; %delete dead exits
          exits(l,2,m) = 0; %delete obsolete deadsum
        end
      end
    end
  end
end

% adjust matrix size
path_metric_array = path_metric_array(1:states_amount,:);
end

######################################## T I K Z ######################################################


if segments_amount < 3
  fontsize = "\\normalsize";
elseif segments_amount > 5
  fontsize = "\\tiny";
else
  fontsize = "\\scriptsize";
end

% begin & end
tikz_begin = strcat("\n%%%%%%%%%%%%%%%%%%% T I K Z   S E T T I N G S %%%%%%%%%%%%%%%%%%%\n\n\n% you can adjust your trellis by changing styles and values\n\\documentclass[crop,beamer]{standalone}\n\\usepackage{tikz}\n\\begin{document}\n\\usetikzlibrary{decorations.shapes,calc}\n\\begin{frame}\n\\resizebox{10.8cm}{!}{\n\\begin{tikzpicture}\n% change 'tikzstyle's to personalize the appearance of trellis elements \n\\tikzstyle{every node}=[font=",fontsize,"]");
tikz_end = "\n\n\\end{tikzpicture}\n}\n\\end{frame}\n\\end{document}"; 


x_scale = 9.4/(segments_amount-1);
if states_amount > 4
  y_scale = 9.4/(states_amount-1);
  tikz_styles = strcat(" \n\\tikzstyle{dots}=[draw,circle,inner sep=0.7pt,fill=black!50]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{paths}=[thin, black,-]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{livingpathoutline}=[thick,red,double=red!20,double distance=2pt,join=round,cap=round]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{deadpathoutline}=[thick,black,double=black!20,double distance=2pt,join=round,cap=round]");
  elseif states_amount < 3
  y_scale = (9.4/(states_amount-1))/3;
  tikz_styles = strcat("\n\\tikzstyle{dots}=[draw,circle,inner sep=2pt,fill=black!50]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{paths}=[very thick, black,-]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{livingpathoutline}=[thick,red,double=red!20,double distance=6pt,join=round,cap=round]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{deadpathoutline}=[thick,black,double=black!20,double distance=6pt,join=round,cap=round]");
  else
  y_scale = (9.4/(states_amount-1))/2;
  tikz_styles = strcat(" \n\\tikzstyle{dots}=[draw,circle,inner sep=1.4pt,fill=black!50]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{paths}=[thick, black,-]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{livingpathoutline}=[thick,red,double=red!20,double distance=4pt,join=round,cap=round]");
  tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{deadpathoutline}=[thick,black,double=black!20,double distance=4pt,join=round,cap=round]");
end
tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{pathmetric}=[draw,circle,inner sep=2pt,fill=white,anchor=north east]");
tikz_styles = strcat(tikz_styles,"\n\\tikzstyle{codewordbits}=[rectangle, rounded corners=9pt, fill=white, fill opacity=.6, text opacity=1, text=black]");
tikz_styles = strcat(tikz_styles,"\n% change xscale, yscale and pathmetricposition to resize your diagram");
tikz_styles = strcat(tikz_styles,"\n\\def\\xscale{",num2str(x_scale),"}\n\\def\\yscale{",num2str(y_scale),"}");
tikz_styles = strcat(tikz_styles,"\n\\def\\pathmetricposition{",num2str(0.25),"}");
tikz_styles = strcat(tikz_styles,"\n\\def\\codewordbitspositionfirsthalf{",num2str(0.65),"}");
tikz_styles = strcat(tikz_styles,"\n\\def\\codewordbitspositionsecondhalf{",num2str(0.35),"}");
tikz_styles = strcat(tikz_styles,"\n% change '{1}' to '{0}' to avoid displaying decoding, pathmetric or codeword bits on trellis paths");
tikz_styles = strcat(tikz_styles,"\n\\def\\showdecoding{1}");
tikz_styles = strcat(tikz_styles,"\n\\def\\pathmetric{",num2str(pathmetricswitch),"}");
tikz_styles = strcat(tikz_styles,"\n\\def\\codewordbits{",num2str(cwswitch),"}");



% dots
states_num_string = num2str(states_amount-1);
trellis_num_string = num2str(time_instances-1);
tikz_dots_start_string = "\n\n% dots\n\\foreach \\x in {0,...,";
tikz_dots_one_string = "}{\n\\foreach \\y in {0,...,";
tikz_dots_two_string_a = "}{\n\\node[dots] at (";
tikz_dots_two_string_b = "*\\x,";
tikz_dots_two_string_c = "*\\y) {};    	\n}\n}";
dots_string = strcat(tikz_dots_start_string,trellis_num_string,tikz_dots_one_string,states_num_string,tikz_dots_two_string_a,"\\xscale",tikz_dots_two_string_b,"\\yscale",tikz_dots_two_string_c);

% states
states_string = strcat("\n\n\n%%%%%%%%%%%%%%%%%%%%% T I K Z C O D E %%%%%%%%%%%%%%%%%%%%%\n\n% ", code_string, " trellis\n\n\n% states ");
for i = 1:states_amount
  state_string = num2str(i);
  tikz_states_one_string = "\n\\draw (0,";
  tikz_states_two_string = ") node[anchor=east] {$s_{";
  tikz_states_three_string = "}\\,=\\,";
  tikz_states_four_string = "$\\,\\,};";
  states_string = strcat(states_string,tikz_states_one_string,"\\yscale*",num2str(-i),"+(\\yscale*",num2str(states_amount),tikz_states_two_string,num2str(i-1), tikz_states_three_string,state_string,tikz_states_four_string);
end

% edges
trellis_edges =  "\n\n% edges ";
trellis_edge = " ";
for i = 1:codewords_amount;
  for j = 1:segments_amount;
    if strcmp(bits_str{i,j}," ") == 0
      bit = bits_str{i,j};
      startposition = starts_int{i,j};
      endposition = ends_int{i,j};
      trellis_edge = strcat("\n\\draw[paths] (","\\xscale*",num2str(j-1),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(startposition),") -- (\\xscale*",num2str(j),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(endposition),"); ");
      trellis_edges = strcat(trellis_edges,trellis_edge);
    end
  end
  trellis_edges = strcat(trellis_edges," ");
end

% codewordbits
codewordbits_string =  "\n\n% codewordbits\n\\if\\codewordbits0\n\\else";
cwbits_string = " ";
for i = 1:codewords_amount;
  for j = 1:segments_amount;
    if strcmp(bits_str{i,j}," ") == 0
      bit = bits_str{i,j};
      startposition = starts_int{i,j};
      endposition = ends_int{i,j};
      if (segments_amount/j) >= (segments_amount/(ceil(segments_amount/2)))
        cwbits_string = strcat("\n\\node [codewordbits]at($(","\\xscale*",num2str(j-1),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(startposition),")!\\codewordbitspositionfirsthalf!(\\xscale*",num2str(j),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(endposition),")$) {(",bit,")}; ");
      else
        cwbits_string = strcat("\n\\node [codewordbits]at($(","\\xscale*",num2str(j-1),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(startposition),")!\\codewordbitspositionsecondhalf!(\\xscale*",num2str(j),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(endposition),")$) {(",bit,")}; ");
      end
      codewordbits_string = strcat(codewordbits_string,cwbits_string);
    end
  end
  codewordbits_string = strcat(codewordbits_string," ");
end
codewordbits_string = strcat(codewordbits_string,"\n\\fi ");

% TikZ code for decoding (only executed if decoding is wanted)
if decoding == 0
  else
% received vector
sequence_string = strcat("\n% received vector\n\\if\\showdecoding0\n\\else \n\\draw (0,\\yscale*",num2str(states_amount-1),"+0.8) node[anchor=south east] {$\\mathsf{received\\,\\,vector:}$};");  
for i = 1:segments_amount
  rec_string = received{i,1};
  tikz_sequence_one_string = "\n\\draw (";
  tikz_sequence_two_string = " node[anchor=south] {$(";
  tikz_sequence_three_string = ")$};  ";
  sequence_string = strcat(sequence_string,tikz_sequence_one_string,"\\xscale*",num2str(i-1),"+\\xscale/2,\\yscale*",num2str(states_amount-1),"+0.75)",tikz_sequence_two_string,rec_string,tikz_sequence_three_string);
end
sequence_string = strcat(sequence_string,"\n\\fi ");

% codeword estimate
only_string_1 = strcat("\n\n% codeword estimate\n\\if\\showdecoding0\n\\else \n\\draw(",num2str(0),",\\yscale*",num2str(states_amount-1),"+1.15) node[anchor=south east] {$\\,\\,$};\n\\only<");
only_string_2 = "-";
only_string_3 = ">{";
only_end = "\n}\n";
last_step = time_instances;
codeest_string = strcat(only_string_1,num2str(last_step),only_string_3,"\n\\draw[red] (",num2str(0),",\\yscale*",num2str(states_amount-1),"+1.15) node[anchor=south east] {$\\mathsf{codeword\\,\\,estimate:}$};");  
for i = 1:segments_amount
  alive_count = 0;
  for m = 1:codewords_amount
    if lifespan(m,i) == stillalive
      alive_count = alive_count+1;
      if alive_count == 1
        ce_string = bits_str{m,i};
      elseif alive_count > 1
        ce_string = strcat(ce_string,",\\,\\,",bits_str{m,i});
      end        
    end
  end
  ce_one_string = "\n\\draw[red] (";
  ce_two_string = " node[anchor=south] {$(";
  ce_three_string = ")$};  ";
  codeest_string = strcat(codeest_string,ce_one_string,"\\xscale*",num2str(i-1),"+\\xscale/2",",\\yscale*",num2str(states_amount-1),"+1.15)",ce_two_string,ce_string,ce_three_string);
end
codeest_string = strcat(codeest_string,only_end,"\n\\fi ");

% path metric
weights_string = "\n\n% path metric\n\\if\\showdecoding0\n\\else \n\\if\\pathmetric0\n\\else ";
only_string_1 = "\n\\only<";
only_string_2 = "-";
only_string_3 = ">{";
only_end = "}";
tikz_weights_one_string = "\n\\node[pathmetric] at (";
tikz_weights_two_string = "-\\pathmetricposition) {";
for j=1:segments_amount+1  
  weights_string=strcat(weights_string,only_string_1,num2str(j-1),only_string_2,num2str(length(compression)+1 ),only_string_3);
  for i=1:states_amount
    if path_metric_array(i,j) < 1000
      weightposition = i;
      weights_string = strcat(weights_string,tikz_weights_one_string,"\\xscale*",num2str(j-1),",\\yscale*",num2str(states_amount),"-\\yscale*",num2str(weightposition),tikz_weights_two_string,num2str(path_metric_array(i,j)),"};");
    end
  end
  weights_string = strcat(weights_string,only_end);
end
weights_string = strcat(weights_string,"\n\\fi\n\\fi ");

% temporary path segments
path_string = "\n\n% temporary path segments \n\\if\\showdecoding0\n\\else ";
living_path_red = "\n \\draw[livingpathoutline] (";
dead_path_black = "\n \\draw[deadpathoutline] (";
only_string_1 = "\n\\only<";
only_string_2 = "-";
only_string_3 = ">{";
connection = ") -- (";
comma = ",";
path_end = ");";
only_end = "}";
% trellis paths depending only on lifespans
for j = 1:segments_amount
  for i = 1:codewords_amount
    origin_x_position = strcat("\\xscale*",num2str(j-1));
    arrival_x_position = strcat("\\xscale*",num2str(j));
    if lifespan(i,1,j) != nonexistent
      origin_state = strcat("\\yscale*",num2str(states_amount),"-\\yscale*",num2str(starts_int{i,j}));
      arrival_state = strcat("\\yscale*",num2str(states_amount),"-\\yscale*",num2str(ends_int{i,j}));
      birth = num2str(j);
      if lifespan(i,1,j) < stillalive
        obit = num2str(lifespan(i,1,j)-1);
        death = num2str(lifespan(i,1,j));
        path_string = strcat(path_string,only_string_1,birth,only_string_2,obit,only_string_3);
        path_string = strcat(path_string,living_path_red,origin_x_position,comma,origin_state,connection,arrival_x_position,comma,arrival_state,path_end);
        path_string = strcat(path_string,only_end);
        path_string = strcat(path_string,only_string_1,death,only_string_2,death,only_string_3);
        path_string = strcat(path_string,dead_path_black,origin_x_position,comma,origin_state,connection,arrival_x_position,comma,arrival_state,path_end);
        path_string = strcat(path_string,only_end);
      elseif lifespan(i,1,j) == stillalive
        path_string = strcat(path_string,only_string_1,birth,only_string_2,num2str(segments_amount+1),only_string_3);
        path_string = strcat(path_string,living_path_red,origin_x_position,comma,origin_state,connection,arrival_x_position,comma,arrival_state,path_end);
        path_string = strcat(path_string,only_end);
      elseif lifespan(i,1,j) == stillborn
        path_string = strcat(path_string,only_string_1,birth,only_string_2,birth,only_string_3);
        path_string = strcat(path_string,dead_path_black,origin_x_position,comma,origin_state,connection,arrival_x_position,comma,arrival_state,path_end);
        path_string = strcat(path_string,only_end);
      end
    end
  end
end
path_string = strcat(path_string,"\n\\fi ");

% error bits
biterror_string = "";
if decoding == 1 
 biterror_string = strcat("\n\n % error bits position\n\\if\\showdecoding0\n\\else \n\\draw(",num2str(0-1.15),",\\yscale*",num2str(states_amount-1),"+0.4)");
 biterror_string = strcat(biterror_string,"node[anchor=south west] {$\\,\\,$};","\n\\draw[black] (",num2str(0-2.55),",\\yscale*",num2str(states_amount-1),"+0.4)");
 biterror_string = strcat(biterror_string,"node[anchor=south west] {$\\mathsf{error\\,\\,bits\\,\\,position:}");
 for j = 1:length(errorpositions)
 biterror_string = strcat(biterror_string,"\\,\\,",num2str(errorpositions(j)));
 end
 biterror_string = strcat(biterror_string,"$};","\n\\fi ");
end
end

if decoding == 0
tikz_code = strcat(tikz_begin, tikz_styles,states_string,trellis_edges,codewordbits_string,dots_string,tikz_end);
else  
tikz_code = strcat(tikz_begin, tikz_styles,states_string,sequence_string,codeest_string,biterror_string,path_string,trellis_edges,codewordbits_string,dots_string,weights_string,tikz_end);
end


######################################################## TIKZ END ###########################################################################################################


basename = strrep(filename, '.png', '');
tikz_file = fopen(sprintf('%s.tex', basename), 'w');
fwrite(tikz_file, tikz_code);
fclose(tikz_file)


cmd = 'pdflatex -output-directory=./tmp %s.tex; convert -density 600 -resize 2400x1800 %s.pdf %s.tikz.png ';
cmd = strrep(cmd, '%s', basename);
fprintf('about to execute the command\n%s', cmd);
[status, output] = system(cmd);



if decoding == 0
  for p=0:inue_js_animationNumberOfFrames-1
    copyfile(sprintf('%s.tikz.png', basename), sprintf('%s.png_%d', basename, p));  
  endfor 
else
  for p=0:segments_amount
    copyfile(sprintf('%s.tikz-%d.png', basename, p), sprintf('%s.png_%d', basename, p));  
  endfor 

  for p=segments_amount+1:inue_js_animationNumberOfFrames-1
    copyfile(sprintf('%s.tikz-%d.png', basename, segments_amount), sprintf('%s.png_%d', basename, p));  
  endfor 
endif

tikz_link = ['<a href=./',sprintf('%s.tex', basename),'> TikZ code of the ',code_string,' trellis</a>'];


endfunction


% functions
% converts generatormatrix into trellis oriented matrix
function [trellis_oriented_matrix,index_matrix] = trellis_oriented_form (generatormatrix)
  trellisorientation = false;
  temp_matrix = generatormatrix;
  while trellisorientation == false
    [trellisorientation, poly_one, poly_two, index_matrix] = test_for_trellisorientation(temp_matrix);
    if trellisorientation == false
      resulting_row = mod(temp_matrix(poly_one,:)+temp_matrix(poly_two,:),2);
      index=0;
      if index_matrix(poly_one,3)>=index_matrix(poly_two,3) 
        index = poly_one;
      else
        index = poly_two;
      end
      temp_matrix(index,:) = resulting_row;      
    end
    trellis_oriented_matrix = temp_matrix;
  end
endfunction

% checks for trellisorientation and returns next polynomials for calculation an their length
function [testresult, poly_one, poly_two, index_matrix] = test_for_trellisorientation (generatormatrix)
  a = size((generatormatrix),1);
  b = length(generatormatrix);
  length_till_end = 0;
  start = 0;
  stop = 0;
  length = 0;
  index_matrix = zeros(size(generatormatrix),3);
  for i = 1:a
    for j = 1:b
      if generatormatrix(i,j) == 1
        stop = j;
      endif
      if (stop <= j) && (stop ~= 0)
        length_till_end = length_till_end+1;
        start = b+1 - length_till_end;
        length =  stop - start +1;
      endif
      index_matrix(i,1) = start;
      index_matrix(i,2) = stop;
      index_matrix(i,3) = length;
    endfor
    length_till_end = 0;
    stop = 0;
  endfor
  poly_one = 0;
  poly_two = 0;
  for i = 1:(size(index_matrix,1)-1)
    poly_test=index_matrix(i,1);
    for j = (i+1):size(index_matrix,1)
      if poly_test == index_matrix(j,1)
        poly_one = i;
        poly_two = j;
      end
    end
  end
  if (poly_one == 0) && (poly_two == 0)
    for i = 1:(size(index_matrix,1)-1)
      poly_test=index_matrix(i,2);
      for j = (i+1):size(index_matrix,1)
        if poly_test == index_matrix(j,2)
          poly_one = i;
          poly_two = j;
        end
      end
    end
  end
  if (poly_one == 0) && (poly_two == 0)
    testresult = 1;
  else
    testresult = 0;
  end
endfunction

% returns compression structure for the trellis
function compression = find_compression (trellis_oriented_matrix,index_matrix)
  generator_starts_ends = zeros(2,size(trellis_oriented_matrix,2));
  % collect startpositions of gp in first row and endpositions of gp in second row
  for i = 1:size(index_matrix,1)
    for j = 1:2
      generator_starts_ends(j,index_matrix(i,j)) = 1;
    end
  end
  start_hold = 1;
  start_temp = 0;
  end_hold = 0;
  compression_count = 1;
  compression = zeros(1,size(trellis_oriented_matrix,2));
  % possible compression: connected segments may include max 1 start and max 1 end of an gp.
  for j = 1:size(trellis_oriented_matrix,2)
    if generator_starts_ends(1,j) == 1
      start_temp = j;
    end
    if generator_starts_ends(2,j) == 1 && start_temp != 0
      compression(compression_count) = start_temp - start_hold;
      start_hold = start_temp; 
      end_hold = j;
      compression_count = compression_count+1;
      start_temp = 0;
    elseif generator_starts_ends(2,j) == 1 && j == size(trellis_oriented_matrix,2)
      compression(compression_count) = end_hold+1 - start_hold;
      compression(compression_count+1) = j - end_hold;
      compression_count = compression_count+1;
    end
  end  
  if sum(compression) == size(trellis_oriented_matrix,2)
    compression = compression(1:compression_count);
  else
    compression = compression(1:compression_count);
    compression(1,1) = ceil(size(trellis_oriented_matrix,2)/2);
    compression(1,2) = floor(size(trellis_oriented_matrix,2)/2);
  end
endfunction

function [starts, ends, bits] = reduced_compressed_trellis_product(trellis_oriented_matrix, compression, index_matrix)
  % binary array containing possible messages for codewords
  binary_array = zeros(2^(size(trellis_oriented_matrix,1)),size(trellis_oriented_matrix,1));
  for i = 1:size(binary_array,1)
    binary_number = dec2bin(i-1);
    binary_number_length = length(binary_number);
    for j = binary_number_length:-1:1
      binary_array(i,size(binary_array,2)+1-j) = str2num(binary_number(length(binary_number)+1-j));
    end
  end
  codewords_array = rem(binary_array*trellis_oriented_matrix,2);
  % Trellis Produkt states
  state_transitions_starts_array = cell(2^(size(trellis_oriented_matrix,1)),size(trellis_oriented_matrix,2));
  state_transitions_starts_array(:,:) = "0000";
  state_transitions_ends_array = state_transitions_starts_array;
  for i = 1:size(binary_array,1)
    for j = 1: size(binary_array,2)
      if binary_array(i,j) == 1
        for k = (index_matrix(j,1)+1):(index_matrix(j,2))
          state_transitions_starts_array{i,k}(j) = "1";
        end
        for k = (index_matrix(j,1)):(index_matrix(j,2)-1)
          state_transitions_ends_array{i,k}(j) = "1";
        end
      end
    end
  end
  % group bits, starts and ends according to compression

  for i = 1:size(codewords_array,1)
    for j = 1:length(compression)
      states_of_branches_starts_compressed{i,j} = state_transitions_starts_array{i,size(state_transitions_starts_array,2)+1-sum(compression(j:end))};
      states_of_branches_ends_compressed{i,j} = state_transitions_ends_array{i,sum(compression(1:j))};
      compressed_codewords_bits ="";
      for k = 1:(compression(j))
        compressed_codewords_bits = strcat(compressed_codewords_bits,num2str(codewords_array(i,((1+length(trellis_oriented_matrix))-sum(compression(j:(length(compression))))-1+k))));
      end
      compressed_codewords{i,j} = compressed_codewords_bits;
    end
  end
  % return values
  starts = states_of_branches_starts_compressed;
  ends = states_of_branches_ends_compressed;
  bits = compressed_codewords;
endfunction