Número de errores de caché FIFO

35

Este desafío es realmente simple (¡y un precursor de uno más difícil!).

Dada una matriz de accesos a recursos (simplemente denotada por enteros no negativos) y un parámetro n, devuelve el número de fallos de caché que supondría si nuestra caché tiene capacidad ny utiliza un esquema de expulsión de primero en entrar, primero en salir (FIFO) cuando está lleno .

Ejemplo:

4, [0, 1, 2, 3, 0, 1, 2, 3, 4, 0, 0, 1, 2, 3]
0 = not in cache (miss), insert, cache is now [0]
1 = not in cache (miss), insert, cache is now [0, 1]
2 = not in cache (miss), insert, cache is now [0, 1, 2]
3 = not in cache (miss), insert, cache is now [0, 1, 2, 3]
0 = in cache (hit), cache unchanged
1 = in cache (hit), cache unchanged
2 = in cache (hit), cache unchanged
3 = in cache (hit), cache unchanged
4 = not in cache (miss), insert and eject oldest, cache is now [1, 2, 3, 4]
0 = not in cache (miss), insert and eject oldest, cache is now [2, 3, 4, 0]
0 = in cache (hit), cache unchanged
1 = not in cache (miss), insert and eject oldest, cache is now [3, 4, 0, 1]
2 = not in cache (miss), insert and eject oldest, cache is now [4, 0, 1, 2]
3 = not in cache (miss), insert and eject oldest, cache is now [0, 1, 2, 3]

Entonces, en este ejemplo hubo 9 fallas. Tal vez un ejemplo de código ayude a explicarlo mejor. En Python:

def num_misses(n, arr):
    misses = 0
    cache = []
    for access in arr:
        if access not in cache:
            misses += 1
            cache.append(access)
            if len(cache) > n:
                cache.pop(0)
    return misses

Algunos casos de prueba adicionales (que contienen una pista hacia el próximo desafío, ¿notas algo curioso?):

0, [] -> 0
0, [1, 2, 3, 4, 1, 2, 3, 4] -> 8
2, [0, 0, 0, 0, 0, 0, 0] -> 1
3, [3, 2, 1, 0, 3, 2, 4, 3, 2, 1, 0, 4] -> 9
4, [3, 2, 1, 0, 3, 2, 4, 3, 2, 1, 0, 4] -> 10

El código más corto en bytes gana.

orlp
fuente
15
Estaba mirando la última declaración notice anything curious?por un tiempo ahora ... y me di cuenta, ¿aumentar la capacidad de caché no necesariamente disminuye la cantidad de fallas?
JungHwan Min
@JungHwanMin ¡Correcto! De hecho, lo peor que puede llegar es ilimitado.
orlp
¿Podemos generar el número en unario?
dylnan
99
Conocido como la anomalía de Bélády y FIFO es el ejemplo clásico. La anomalía es ilimitada .
virtualirfan
@dylnan No, lo siento.
orlp

Respuestas:

11

JavaScript (ES6), 55 bytes

Método # 1: el caché sobrescribe la entrada

Toma entrada en la sintaxis de curry (cache_size)(list).

n=>a=>a.map(x=>a[a.indexOf(x,k>n&&k-n)<k||k++]=x,k=0)|k

Pruébalo en línea!

¿Cómo?

Sobrescribimos la matriz de entrada a [] con el caché, usando un puntero separado k inicializado a 0 .

Usamos a.indexOf(x, k > n && k - n) < kpara probar si x está en el caché.

El caché no puede crecer más rápido de lo que se recorre la matriz original, por lo que se garantiza que cada valor se encontrará, ya sea dentro o más allá de la ventana del caché (es decir indexOf(), nunca devolverá -1 ).

Un valor está en la memoria caché si se encuentra en un índice entre max (0, k - n) y k - 1 (ambos límites incluidos), en cuyo caso hacemos un [verdadero] = x . Esto solo afecta a una propiedad del objeto subyacente detrás de [] pero no altera la matriz a [] . De lo contrario, hacemos un [k ++] = x .

Ejemplo

A continuación se detallan los diferentes pasos para la entrada [1, 1, 2, 3, 3, 2, 1, 4]con un tamaño de caché de 2 :

  • bordes en negrita: puntero map ()
  • paréntesis: puntero de caché k
  • naranja: ventana de caché actual
  • amarillo: valores de caché caducados

Método 1


JavaScript (ES6), 57 bytes

Método # 2: el caché se agrega al final de la entrada

Toma entrada en la sintaxis de curry (cache_size)(list).

n=>a=>a.map(x=>n*~a.indexOf(~x,-n)||a.push(~x)&k++,k=0)|k

Pruébalo en línea!

¿Cómo?

Debido a que se garantiza que la matriz de entrada a [] contiene enteros no negativos, podemos agregar de forma segura la caché al final de a [] utilizando el complemento único ~ x de cada valor x .

Usamos n * ~a.indexOf(~x, -n)para probar si ~ x se encuentra entre los últimos n valores. Cuando esta prueba falla, agregamos ~ x a a [] e incrementamos el número de errores k .

Ejemplo

A continuación se muestran los diferentes pasos para el mismo ejemplo anterior, utilizando este método. Debido a que los valores de caché simplemente se agregan al final de la matriz, no hay un puntero de caché explícito.

método # 2

Arnauld
fuente
9

Python 2 , 58 bytes

lambda n,a:len(reduce(lambda c,i:[i][i in c[:n]:]+c,a,[]))

Pruébalo en línea!

Gracias a ovs por 3 bytes, y xnor por 3 más.

Lynn
fuente
Debería poder guardar bytes colocando un conjunto después c+=, ya que por alguna razón se convierte en una lista para usted.
xnor
(Ah, sí, c+={i}-set(c[-n:])funciona, es positivo n. Pero Nimi señaló que eso c[-n:]está mal n == 0, así que no puedo usar +=, y por lo tanto ese truco - muy mal.)
Lynn
1
@ Lynn Ah, ya veo. reduceTodavía guarda bytes: lambda n,a:len(reduce(lambda c,i:[i][i in c[:n]:]+c,a,[])).
xnor
7

R , 69 64 62 bytes

function(n,A,K={}){for(i in A)K=c(i[!i%in%K[0:n]],K);sum(K|1)}

Pruébalo en línea!

¡Gracias a JayCe por sugerir algunas mejoras, y DigEmAll por otra pareja!

Giuseppe
fuente
Supongo que el +frente Fes para f(0,{})devolver 0?
JayCe
@ JayCe sí, un golf clásico en tándem con Fun valor de retorno preinicializado.
Giuseppe
1
Una pequeña mejora . Además, si se acepta la salida unaria, probablemente pueda guardar algunos bytes.
JayCe
¡@JayCe encontró algunos bytes más!
Giuseppe
1
@JDL, sí, una pena, qpero sigue siendo una buena idea Usar NAes menos bueno que usar {}ya que realmente me importa la longitud aquí (y en realidad no estoy sacando elementos del caché).
Giuseppe
5

Haskell, 61 58 bytes

n!a|let(a:b)#c|elem a c=b#c|1<2=1+b#take n(a:c);_#_=0=a#[]

Pruébalo en línea!

n!a|      =a#[]     -- take input 'n' and a list 'a'
                    -- and call # with the initial list and an empty cache
 let                -- bind function '#':
  (a:b)#c           -- if there's at least one element 'a' left in the list
     |elem a c=b#c  --  and it's in the cache, go on with the same cache
                    --  and the remainder of the list
     |1<2=          -- else (i.e. cache miss)
          1+        --  add one to the recursive call of
       b#           --  the remainder of the list and 
       take n(a:c)  --  the first n elements of 'a' prepended to the cach
 _#_=0              -- if there's no element in the list, return 0

Editar: -3 bytes gracias a @Lynn.

nimi
fuente
5

05AB1E , 17 16 bytes

)svDyå_i¼y¸ìI£]¾

Pruébalo en línea!

Explicación

)                   # wrap the stack in a list
 sv                 # for each item y in input list
   D                # duplicate current list
    yå_i            # if y is not contained in the current list
        ¼           # increment counter
         y¸ì        # prepend y to the current list
            I£      # keep the first input elements
              ]¾    # end loop and push counter
Emigna
fuente
@nimi: ¡Gracias! Se
corrigió
5

Kotlin , 82 69 bytes

{a,n->a.fold(List(0){0}){c,v->if(v!in c.takeLast(n))c+v else c}.size}

Toma la entrada como un IntArray, no el típico List<Int>(que no debería ser un problema). Esto utiliza el enfoque de "construir un historial de caché y contar su longitud".

Pruébalo en línea!

Explicación

{ a, n ->                         // lambda where a is accesses and n is cache size
    a.fold(List(0){0}) { c, v ->  // fold on empty list
        if(v !in c.takeLast(n))   // if resource is not in last n cache inserts
            c + v                 // insert to cache list
        else
            c                     // return cache as is
    }.size                        // length of cache list is number of inserts
}

Crear una lista vacía

Kotlin no tiene literales de colección, pero tiene algunas funciones para crear nuevas colecciones.

La forma correcta de crear un vacío List<Int>es simplemente:

List<Int>()

pero es más corto si abusamos del tamaño y los argumentos del inicializador para hacer esto:

List(0){0}
List(0)       // List of size 0
       { 0 }  // with generator returning 0

Como el generador lambda devuelve 0, Kotlin infiere el tipo de esta lista como List<Int>, y el tamaño de 0 significa que esta lista está vacía.

caracol_
fuente
4

Perl 6 , 48 bytes

{my@c;$_@c.tail($^n)||push @c,$_ for @^o;+@c}

Pruébalo

{  # bare block with placeholder params $n,@o

  my @c; # cache


      $_  @c.tail($^n) # is the current value in the last bit of the cache
    ||
      push @c, $_       # if not add it to the cache

  for                   # do this for all of

    @^o;                # the input array


  +@c                   # numify the cache (the count)
}
Brad Gilbert b2gills
fuente
4

Java 8, 96 bytes

Una lambda al curry que toma un tamaño de caché ( int) y una lista de acceso (mutable java.util.List<Integer>) y devuelve un int.

s->a->{int w=0,m=0,i;for(int r:a)m+=(i=a.indexOf(r))<w&i<s?0:s<1?1:1+0*a.set(w++%s,r);return m;}

Pruébalo en línea

Sin golf

Esto usa los primeros (hasta) sespacios en la lista de entrada para el caché.

s ->
    a -> {
        int
            w = 0,
            m = 0,
            i
        ;
        for (int r : a)
            m +=
                (i = a.indexOf(r)) < w & i < s ?
                    0
                    s < 1 ?
                        1
                        : 1 + 0*a.set(w++ % s, r)
            ;
        return m;
    }

Expresiones de gratitud

  • corrección de errores gracias a nimi
Jakob
fuente
4

Pyth ,  16 15 18 14  13 bytes

Guardado 1 byte gracias a isaacg .

luaW-H>QGGHEY

¡Banco de pruebas!

Este desafío se adapta muy bien a la uestructura de Pyth .

Cómo funciona

luaW-H>QGGHEY     Full program. Q = the cache length, E = the list.
 u         E      Reduce E with G = current value and H = corresponding element
            Y     With starting value Y, which is preinitialised to [] (empty list).
   W              Conditional application. If...
    -H            ... Filtering H on absence of...
      >QG         ... The last Q elements of G... 
                  ... Yields a truthy value (that is, H is not in G[-Q:]), then...
  a      GH       ... Append H to G.
                  ... Otherwise, return G unchanged (do not append H at all).
l                  Get the length of the result.
Sr. Xcoder
fuente
aW-H>QGGHlate ?}H<GQG+HGpor 1
isaacg
@isaacg ¡Gracias! Inicialmente lo había hecho +G*]H!}H>QG, pero cuando jugué al golf no pensé en W... ¡ Bien !
Sr. Xcoder
¿Qué hace exactamente u?
dylnan
@dylnan ues un operador de reducción con valor inicial . Como Jelly'sƒ
Mr. Xcoder
2

Japt, 16 bytes

;£A¯V øX ªAiXÃAl

Intentalo


Explicación

                     :Implicit input of array U and integer V
 £                   :Map over each X in U
; A                  :  Initially the empty array
   ¯V                :  Slice to the Vth element
      øX             :  Contains X?
         ª           :  Logical OR
          AiX        :  Prepend X to A
             Ã       :End map
              Al     :Length of A
Lanudo
fuente
1

K4 , 42 40 bytes

Solución:

{*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[x]\y}

Ejemplos:

q)k)f:{*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[x]\y}
q)f[0;1 2 3 4 1 2 3 4]
8
q)f[2;0 0 0 0 0 0 0]
1
q)f[3;3 2 1 0 3 2 4 3 2 1 0 4]
9
q)f[4;3 2 1 0 3 2 4 3 2 1 0 4]
10

Explicación:

Para la función interna, y es el caché, z es la solicitud y x es el tamaño del caché.

{*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[x]\y} / the solution
{                                      } / lambda taking 2 args
       {                         }       / lambda taking 3 args
                                  [x]\y  / iterate over lambda with each y
                              *|y        / last (reverse, first) y
                            y:           / assign to y
                       z in              / is z in y?
                      ~                  / not 
                    r:                   / assign result to r (true=1,false=0)
           ( ;     )                     / 2-element list
                z,y                      / join request to cache
              x#                         / take x from cache (limit size)
            y                            / (else) return cache unchanged
          ,                              / enlist this result
        r,                               / join with r
     1_                                  / drop the first result
  1+/                                    / sum up (starting from 1)
 *                                       / take the first result

Notas:

Probablemente haya una mejor manera de hacer todo esto, pero esta es la primera forma en que se me ocurrió.

La función se puede ejecutar así para 36 bytes :

q)k)*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[4]\3 2 1 0 3 2 4 3 2 1 0 4
10

Alternativa: usar una variable global para almacenar el estado (no muy similar a K), 42 bytes :

{m::0;(){$[z in y;y;[m+:1;x#z,y]]}[x]\y;m}
callejero
fuente
1

Brain-Flak , 172 bytes

(([{}]<>)<{({}(()))}{}>)<>([]){{}<>((({})<{({}()<<>(({})<({}<>({}<>))>)<>>)}{}>)<<>(({})([{}]<>{<>(){[()](<{}>)}{}<><({}()<<>({}<>)>)>}{})){(<{}{}>)}{}>)<>([])}{}<>({}[]<>)

Pruébalo en línea!

# Initialize cache with n -1s (represented as 1s)
(([{}]<>)<{({}(()))}{}>)<>

# For each number in input
([]){{}

    # Keep n on third stack
    <>((({})<

        # For last n cache entries, compute difference between entry and new value
        {({}()<<>(({})<({}<>({}<>))>)<>>)}{}

    >)<

        # Get negation of current entry and...
        <>(({})([{}]<>

            {

                # Count cache hits (total will be 1 or 0)
                <>(){[()](<{}>)}{}

                # while moving entries back to right stack
                <><({}()<<>({}<>)>)>

            }{}

        ))

        # If cache hit, don't add to cache
        {(<{}{}>)}{}

    >)

<>([])}{}

# Compute cache history length minus cache size (to account for the initial -1s)
<>({}[]<>)
Nitrodon
fuente
1

Jalea , 18 bytes

Ṗɼṛ;ɼe®Uḣ⁴¤C$¡€ṛLɼ

Pruébalo en línea!

Toma la lista como primer argumento y la capacidad de caché como segundo argumento.

Ṗɼṛ;ɼe®Uḣ⁴¤C$¡€ṛLɼ
 ɼ                 Apply to the register:
Ṗ                  Pop. This initializes the register to the empty list.
  ṛ                Right argument. Yields the list of addresses.
              €    For each element in the list
             ¡     If{
     e                 the element is in
          ¤            nilad{
      ®                      the register
       U                     reversed
        ḣ                    first...
         ⁴                   (cache depth) number of elements
                             }
           C           Complement. 1 <-> 0. Easier to type this than "not".
            $          Combines everything up to `e` into a monad
                      }
                    Then{
    ɼ                    Apply to the register and store the result
   ;                     Append the element
                        }
                ṛ   Right argument:
                  ɼ Apply to the register:
                 L  Length
dylnan
fuente
1

Ruby , 43 40 bytes

->s,a,*r{a.count{|*x|r!=r=(r|x).pop(s)}}

Pruébalo en línea!

Gracias histocrat por afeitar 3 bytes.

GB
fuente
1
¡Buena respuesta! Puede guardar un par de bytes inicializando r como parte de la lista de argumentos: ->s,a,*rque también proporciona la característica adicional de que la persona que llama puede cebar el caché al pasar argumentos adicionales :)
histocrat
Ah, y de manera similar para lanzar xen una matriz:.count{|*x|
histocrat
1

C (gcc) , 112 110 108 bytes

f(x,y,z)int*y;{int*i=y+z,b[x],m=0;for(wmemset(b,z=-1,x);i-y;y++)wmemchr(b,*y,x)?:++m*x?b[z=++z%x]=*y:0;x=m;}

Pruébalo en línea!

Ligeramente menos golfizado

f(x,y,z)int*y;{
 int*i=y+z,b[x],m=0;
 for(wmemset(b,z=-1,x);i-y;y++)
  wmemchr(b,*y,x)?:
   ++m*
   x?
    b[z=++z%x]=*y
   :
    0;
 x=m;
}
techo
fuente
0

C (gcc) , 156 bytes

s,n,m,i,j;f(x,_)int*_;{int c[x];n=m=0;for(i=0;i<x;++i)c[i]=-1;for(i=s=0;_[i]>=0;++i,s=0){for(j=0;j<x;++j)s|=(c[j]==_[i]);if(!s){c[n++]=_[i];m++;n%=x;}}x=m;}

Pruébalo en línea!

Descripción:

s,n,m,i,j;                       // Variable declaration
f(x,_)int*_;{                    // F takes X (the cache size) and _ (-1-terminated data)
    int c[x];                    // declare the cache
    n=m=0;                       // next queue insert pos = 0, misses = 0
    for(i=0;i<x;++i)c[i]=-1;     // initialize the cache to -1 (invalid data)
    for(i=s=0;_[i]>=0;++i,s=0){  // for each datum in _ (resetting s to 0 each time)
        for(j=0;j<x;++j)         // for each datum in cache
            s|=(c[j]==_[i]);     // set s if item found
        if(!s){                  // if no item found
            c[n++]=_[i];         // add it to the cache at position n
            m++;                 // add a mis
            n%=x;                // move to next n position (with n++)
        }} x=m;}                 // 'return' m by assigning to first argument
LambdaBeta
fuente
Sugerir en wmemset(c,-1,x)lugar de n=m=0;for(i=0;i<x;++i)c[i]=-1, en n=m=i=s=0lugar de i=s=0, en for(j=x;j--;)lugar de for(j=0;j<x;++j)y en s||(c[n++]=_[i],m++,n%=x);lugar deif(!s){c[n++]=_[i];m++;n%=x;}
ceilingcat
0

Jalea , 17 bytes

Ṗœ|Ṛḣ⁴$Ṛʋ\-;⁸e"ċ0

Pruébalo en línea!

Programa completo

Argumento 1: pila (Python 3 listde integers)
Argumento 2: n(Python 3 integer)

Erik el Outgolfer
fuente
0

Óxido , 129 bytes

|l:&[_],s|if s>0{let(mut c,mut m)=(vec![-1;s],0);for n in l.iter(){if!c.contains(n){c.remove(0);c.push(*n);m+=1;}}m}else{l.len()}

Pruébalo en línea!

Sin golf

|l: &[isize], s: usize| {
    if s > 0 {
        let mut c = vec![-1; s];
        let mut m = 0;
        for n in l.iter() {
            if !c.contains(n) {
                c.remove(0);
                c.push(*n);
                m += 1;
            }
        }
        m
    } else {
        l.len()
    }
}
Herman L
fuente