In [1]:

    def produceArrayN(n: Int) = {
        def fifthyFifthyRat = if(scala.util.Random.nextBoolean) 1 else 0
        Array.fill(n)(fifthyFifthyRat)
    }

    implicit class Entangle(b: Array[Int]) {

      def entangleWith(a: Array[Int]): Array[Int] = {
        var bbb = b.toList
        def pull(value: Int) = {
          val i = Option(bbb.indexWhere(_ == value)).filter(_ != -1).getOrElse(0)
          val res = bbb(i)
          bbb = bbb.patch(i, Nil, 1) //remove i-th element from bbb
          res
        }
        val newb = (a zip b).map{
            case (aa, bb) =>
            if (aa == bb && aa == 1) pull(0) else pull(bb)
        }
        newb
      }

    }

    def analyze(n: Int) = {

        def mean(aa: Array[Int]) = aa.count(_ == 1).toDouble / aa.size
        def means(aa: Array[(Int, Int)]) = mean(aa.map(_._1)) -> mean(aa.map(_._2))

        def score(aa: Array[(Int, Int)]) = aa.count{case (a,b) => a * b == 0}.toDouble / aa.size

        case class Report(entangledE: (Double, Double), originalE: (Double, Double), entangledScore: Double, originalScore: Double)

        val left = produceArrayN(n)
        val right = produceArrayN(n)

        val entRight = right entangleWith left
        val entangled = left zip entRight
        val original = left zip right

        Report(means(entangled), means(original), score(entangled), score(original))
    }

Out[1]:

    defined function produceArrayN
    defined class Entangle
    defined function analyze

In [14]:

    import $ivy.`org.plotly-scala::plotly-jupyter-scala:0.3.0`

    import plotly._
    import plotly.element._
    import plotly.layout._
    import plotly.JupyterScala._

    plotly.JupyterScala.init()

    val epochs = 128
    val reports = (1 to epochs).toList.map(_ => analyze(9036))

    val step = 0.01

    val toPlot = Map(
        "entangledLeft" -> reports.map(_.entangledE._1),
        "originalLeft" -> reports.map(_.originalE._1),
        "entangledRight" -> reports.map(_.entangledE._2),
        "originalRight" -> reports.map(_.originalE._2)
    )

    val plot = toPlot map {
        case (name, ent) =>
            val x = (0.1 to 1.0 by step).toList
            val y = x.map{xx =>
              ent.count(m => m > xx && m < xx + step)
            }
            Scatter(x, y, name = name)
    }

    plot.toList.plot()

    val plot2 = List(
        Scatter(1 to epochs, reports.map(_.entangledScore), name = "entangled"),
        Scatter(1 to epochs, reports.map(_.originalScore), name = "original")
    )

    plot2.plot()

    val entangledScore = reports.map(_.entangledScore).sum / epochs
    val originalScore = reports.map(_.originalScore).sum / epochs

    println("Average score:" + entangledScore + " compared to original " + originalScore)

    Average score:0.8329935466467464 compared to original 0.7494769187140329

Out[14]:

    import $ivy.$

    import plotly._

    import plotly.element._

    import plotly.layout._

    import plotly.JupyterScala._

    epochs: Int = 128
    reports: List[Report forSome { type Report <: AnyRef with Product with Serializable{val entangledE: (Double, Double);val originalE: (Double, Double);val entangledScore: Double;val originalScore: Double;def copy(entangledE: (Double, Double),originalE: (Double, Double),entangledScore: Double,originalScore: Double): Report;def copy$default$1: (Double, Double);def copy$default$2: (Double, Double);def copy$default$3: Double;def copy$default$4: Double} }] = List(
      Report((0.5025453740593183,0.4953519256308101),(0.5025453740593183,0.4953519256308101),0.8362107127047366,0.7504426737494466),
      Report((0.49922532093846833,0.4950199203187251),(0.49922532093846833,0.4950199203187251),0.8385347498893315,0.7537627268702966),
      Report((0.49369189907038513,0.5073041168658698),(0.49369189907038513,0.5073041168658698),0.835436033643205,0.7491146525011066),
      Report((0.4960159362549801,0.5044267374944665),(0.4960159362549801,0.5044267374944665),0.8352146967684816,0.7547587428065515),
      Report((0.50066401062417,0.5022133687472333),(0.50066401062417,0.5022133687472333),0.834108012394865,0.7487826471890217),
      Report((0.49424524125719344,0.49778663125276673),(0.49424524125719344,0.497786...
    step: Double = 0.01
    toPlot: Map[String, List[Double]] = Map(
      "entangledLeft" -> List(
        0.5025453740593183,
        0.49922532093846833,
        0.49369189907038513,
        0.4960159362549801,
        0.50066401062417,
        0.49424524125719344,
        0.50066401062417,
        0.5064187693669765,
        0.4995573262505533,
        0.5034307215582116,
    ...
    plot: collection.immutable.Iterable[Scatter] = List(
      Scatter(
        Some(
          Doubles(
            List(
              0.1,
              0.11,
              0.12,
              0.13,
              0.14,
              0.15000000000000002,
              0.16000000000000003,
    ...
    res13_11: String = "plot-381049847"
    plot2: List[Scatter] = List(
      Scatter(
        Some(
          Doubles(
            Vector(
              1.0,
              2.0,
              3.0,
              4.0,
              5.0,
              6.0,
              7.0,
    ...
    res13_13: String = "plot-1730584006"
    entangledScore: Double = 0.8329935466467464
    originalScore: Double = 0.7494769187140329

In [ ]: