### Question:
MultinomialVertex extends VertexImpl<IntegerTensor, IntegerVertex> implements IntegerVertex, ProbabilisticInteger, SamplableWithManyScalars<IntegerTensor> { @Override public IntegerTensor sampleWithShape(long[] shape, KeanuRandom random) { return Multinomial.withParameters(n.getValue(), p.getValue(), validationEnabled).sample(shape, random); } MultinomialVertex(@LoadShape long[] tensorShape,
                             @LoadVertexParam(N_NAME) Vertex<IntegerTensor, ?> n,
                             @LoadVertexParam(P_NAME) Vertex<DoubleTensor, ?> p); @ExportVertexToPythonBindings  MultinomialVertex(Vertex<IntegerTensor, ?> n, Vertex<DoubleTensor, ?> p);  MultinomialVertex(int n, Vertex<DoubleTensor, ?> p);  MultinomialVertex(int n, DoubleTensor p);  MultinomialVertex(IntegerTensor n, Vertex<DoubleTensor, ?> p);  MultinomialVertex(IntegerTensor n, DoubleTensor p); @Override double logProb(IntegerTensor x); @Override Map<Vertex, DoubleTensor> dLogProb(IntegerTensor x, Set<? extends Vertex> withRespectTo); @Override IntegerTensor sampleWithShape(long[] shape, KeanuRandom random); @SaveVertexParam(P_NAME) DoubleVertex getP(); @SaveVertexParam(N_NAME) IntegerVertex getN();  }### Answer:
@Test public void itThrowsIfTheSampleShapeIsNotBroadcastableToTheVertexShape() { thrown.expect(IllegalArgumentException.class); thrown.expectMessage( "Shape [2, 2] is incompatible with n shape [4] and p shape [4, 2]." + " It must be broadcastable with [4, 2]" ); IntegerTensor n = IntegerTensor.create(100, 200, 300, 400); DoubleTensor p = DoubleTensor.create(new double[]{ 0.5, 0.5, 0.25, 0.75, 0.3, 0.7, 0.4, 0.6 }, 4, 2); MultinomialVertex multinomialVertex = new MultinomialVertex(n, p); multinomialVertex.setValidationEnabled(true); multinomialVertex.sampleWithShape(new long[]{2, 2}); }
@Test public void doesAllowSampleWithShapeThatIsBroadcastableWithVertexShape() { IntegerTensor n = IntegerTensor.create(100, 200, 300, 400); DoubleTensor p = DoubleTensor.create(new double[]{ 0.1, 0.9, 0.2, 0.8, 0.3, 0.7, 0.4, 0.6 }, 4, 2); MultinomialVertex multinomialVertex = new MultinomialVertex(n, p); IntegerTensor sample = multinomialVertex.sampleWithShape(new long[]{2, 4, 2}, KeanuRandom.getDefaultRandom()); assertThat(sample, hasShape(2, 4, 2)); }
@Category(Slow.class) @Test public void samplingProducesRealisticMeanAndStandardDeviation() { int sampleCount = 10000; DoubleTensor p = DoubleTensor.create(0.1, 0.2, 0.3, 0.4); int n = 500; MultinomialVertex vertex = new MultinomialVertex(n, p); IntegerTensor samples = vertex.sampleWithShape(new long[]{sampleCount, 4}); assertThat(samples, hasShape(sampleCount, 4)); for (int i = 0; i < samples.getShape()[1]; i++) { IntegerTensor sampleForIndexI = samples.slice(1, i); Double probability = p.getValue(i); double mean = sampleForIndexI.toDouble().mean().scalar(); double std = sampleForIndexI.toDouble().standardDeviation().scalar(); double epsilonForMean = 0.5; double epsilonForVariance = 5.; assertEquals(n * probability, mean, epsilonForMean); assertEquals(n * probability * (1 - probability), std * std, epsilonForVariance); } }