/* * Quasar: lightweight threads and actors for the JVM. * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.actors; import co.paralleluniverse.common.test.TestUtil; import co.paralleluniverse.fibers.Fiber; import co.paralleluniverse.fibers.SuspendExecution; import co.paralleluniverse.strands.channels.Channels; import co.paralleluniverse.strands.dataflow.Val; import java.math.BigInteger; import java.util.Arrays; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; import org.junit.rules.TestRule; /** * * @author eitan */ public class PascalTriangle { @Rule public TestName name = new TestName(); @Rule public TestRule watchman = TestUtil.WATCHMAN; final MailboxConfig mailboxConfig = new MailboxConfig(4, Channels.OverflowPolicy.THROW); public PascalTriangle() { } @Ignore @Test public void testSeqPascalSum() { int maxLevel = 800; BigInteger[] bi = new BigInteger[1]; bi[0] = BigInteger.ONE; BigInteger[] nbi = null; for (int i = 1; i < maxLevel; i++) { nbi = new BigInteger[bi.length + 1]; nbi[0] = BigInteger.ONE; for (int j = 1; j < nbi.length - 1; j++) { nbi[j] = bi[j].add(bi[j - 1]); } nbi[nbi.length - 1] = BigInteger.ONE; bi = nbi; } // System.out.println(Arrays.toString(nbi)); BigInteger sum = BigInteger.ZERO; for (int i = 0; i < nbi.length; i++) { sum = sum.add(nbi[i]); } assertEquals(BigInteger.valueOf(2).pow(maxLevel - 1), sum); } @Test public void testPascalSum() throws Exception { int maxLevel = 20; //800 Val<BigInteger> res = new Val<>(); new Fiber<Void>(new PascalNode(res, 1, BigInteger.ONE, true, null, maxLevel)).start(); assertEquals(BigInteger.valueOf(2).pow(maxLevel - 1), res.get(10, TimeUnit.SECONDS)); } static class PascalNodeMessage { } static class RightBrother extends PascalNodeMessage { final ActorRef<PascalNodeMessage> node; final BigInteger val; public RightBrother(ActorRef<PascalNodeMessage> pn, BigInteger result) { this.node = pn; this.val = result; } } static class Nephew extends PascalNodeMessage { final ActorRef<PascalNodeMessage> node; public Nephew(ActorRef<PascalNodeMessage> pn) { this.node = pn; } } class PascalNode extends BasicActor<PascalNodeMessage, Void> { final Val<BigInteger> result; int level; int pos; BigInteger val; boolean isRight; ActorRef<PascalNodeMessage> left; int maxLevel; Val<BigInteger> leftResult = new Val<>(); Val<BigInteger> rightResult = new Val<>(); public PascalNode(Val<BigInteger> result, int level, BigInteger val, boolean isRight, ActorRef<PascalNodeMessage> left, int maxLevel) { super(mailboxConfig); this.result = result; this.level = level; this.val = val; this.isRight = isRight; this.left = left; this.maxLevel = maxLevel; } @Override protected Void doRun() throws InterruptedException, SuspendExecution { if (level == maxLevel) { result.set(val); return null; } ActorRef<PascalNodeMessage> leftChild; if (left != null) { left.send(new RightBrother(ref(), val)); leftChild = receive(Nephew.class).node; } else leftChild = new PascalNode(leftResult, level + 1, val, false, null, maxLevel).spawn(); final RightBrother rb = isRight ? null : receive(RightBrother.class); final ActorRef<PascalNodeMessage> rightChild = new PascalNode(rightResult, level + 1, val.add(rb == null ? BigInteger.ZERO : rb.val), isRight, leftChild, maxLevel).spawn(); if (rb != null) rb.node.send(new Nephew(rightChild)); if (left == null) result.set(leftResult.get().add(rightResult.get())); else result.set(rightResult.get()); return null; } } }