Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add double auction trait #5

Merged
merged 30 commits into from Mar 23, 2017
Merged

Add double auction trait #5

merged 30 commits into from Mar 23, 2017

Conversation

davidrpugh
Copy link

@bherd I have added a quick sketch of the interface for a DoubleAuction. Up until now everything has been immutable, however at this point I think it is time to think about encapsulating mutable state. In particular I am thinking about have the auction store a mutable reference to its immutable order book.

@davidrpugh
Copy link
Author

@bherd-rb @rafabap I have pushed a new interface for an immutable auction on which I would like some feedback. Whether or not auctions are immutable is a fairly significant design decision. My current justification for making auctions immutable is that this leaves the handling of concurrency issues in the hands of the user.

@bherd-rb I would like to make this the subject of our talk on Thursday. @rafabap you are welcome to join if interested.

@bherd-rb
Copy link
Contributor

bherd-rb commented Mar 16, 2017

@davidrpugh I have a strange problem when trying to access the double auction from within Java. This is my code:

public class App {
    public static void main( String[] args ) {
      // note: that's the only way I can call the function. I haven't figured out how to pass a type parameter.         
      DoubleAuction<Service> auction = DoubleAuction$.MODULE$.withEmptyOrderBook(); 
    }
}

When I compile and run the example, this is the output:

Exception in thread "main" java.lang.NoSuchMethodError: scala.math.PartialOrdering.$init$(Lscala/math/PartialOrdering;)V
	at org.economicsl.auctions.PriceOrdering$.<init>(Price.scala:41)
	at org.economicsl.auctions.PriceOrdering$.<clinit>(Price.scala)
	at org.economicsl.auctions.Price$.<init>(Price.scala:27)
	at org.economicsl.auctions.Price$.<clinit>(Price.scala)
	at org.economicsl.auctions.multiunit.SinglePricePoint$.ordering(SinglePricePoint.scala:56)
	at org.economicsl.auctions.singleunit.SingleUnit$.ordering(SingleUnit.scala:42)
	at org.economicsl.auctions.singleunit.LimitAskOrder$.ordering(LimitAskOrder.scala:28)
	at org.economicsl.auctions.singleunit.DoubleAuction$.withEmptyOrderBook(DoubleAuction.scala:57)
	at com.bosch.de.App.main(App.java:21)

I first thought it has to do with the missing type parameter in the call to withEmptyOrderBook(), so I modified the ESL code as follows (just for testing purposes):

object DoubleAuction {
  def withEmptyOrderBook[T <: Tradable](t : T): DoubleAuction[T] = {
    new DoubleAuction(FourHeapOrderBook.empty[T])
  }
}

I then modified my Java code as follows:

public class App {
    public static void main( String[] args ) {
      DoubleAuction<Service> auction = DoubleAuction$.MODULE$.withEmptyOrderBook(new Service()); 
    }
}

No difference. Still the same error. Do you have any ideas?!

@davidrpugh
Copy link
Author

@bherd-rb What version of Scala are you using? Is it different than 2.12.1 that I am using?

@davidrpugh
Copy link
Author

Have you had trouble creating an empty FourHeapOrderBook before? The full signature for that method is as follows...

def empty[T <: Tradable](implicit askOrdering: Ordering[LimitAskOrder[T]], bidOrdering: Ordering[LimitBidOrder[T]]): FourHeapOrderBook[T] = {
    val matchedOrders = MatchedOrders.empty(askOrdering.reverse, bidOrdering.reverse)
    val unMatchedOrders = UnMatchedOrders.empty(askOrdering, bidOrdering)
    new FourHeapOrderBook(matchedOrders, unMatchedOrders)
  }

Note the implicit parameters. The scala compiler with automatically detect that the required orderings are defining in the companion objects of LimitAskOrder and LimitBidOrder and use them when creating the instance of FourHeapOrderBook. Perhaps this bit of compiler magic is causing the issue...

@bherd-rb
Copy link
Contributor

bherd-rb commented Mar 16, 2017

@davidrpugh I'm using 2.11.6. Yes, I think you might be right. It worked before. I'll see if I can find a solution or, at least, narrow down the problem.

@davidrpugh
Copy link
Author

@bherd-rb See if this new commit fixes the problem. I had left out the implicit parameters from the withEmptyOrderBook method. I have now added them.

@bherd-rb
Copy link
Contributor

@davidrpugh Ok thanks, will give it a try. When I wrap the creation of the auction into a separate Scala object that just returns an object of DoubleAuction<T>, then it seems to work.

@bherd-rb
Copy link
Contributor

@davidrpugh Still the same problem. I create the auction from Java as follows:

DoubleAuction<Service> auction = DoubleAuction.withEmptyOrderBook(
            SinglePricePoint$.MODULE$.<LimitAskOrder<Service>>ordering(),
            SinglePricePoint$.MODULE$.<LimitBidOrder<Service>>ordering().reverse());

This is the result:

Exception in thread "main" java.lang.NoSuchMethodError: scala.math.PartialOrdering.$init$(Lscala/math/PartialOrdering;)V
	at org.economicsl.auctions.PriceOrdering$.<init>(Price.scala:41)
	at org.economicsl.auctions.PriceOrdering$.<clinit>(Price.scala)
	at org.economicsl.auctions.Price$.<init>(Price.scala:27)
	at org.economicsl.auctions.Price$.<clinit>(Price.scala)
	at org.economicsl.auctions.multiunit.SinglePricePoint$.ordering(SinglePricePoint.scala:56)
	at com.bosch.de.AuctionTest.<init>(AuctionTest.java:15)
	at com.bosch.de.AuctionTest.main(AuctionTest.java:20)

Interestingly, I get the same error if I wrap the creation. This is the Scala creation class:

class AuctionCreator[T <: Tradable] {
  val createAuction = DoubleAuction.withEmptyOrderBook[T](SinglePricePoint.ordering, SinglePricePoint.ordering.reverse)
}

For convenience, I created a Java equivalent:

public class JAuctionCreator<T extends Tradable> {
    public DoubleAuction<T> createAuction() {
        return new AuctionCreator<T>().createAuction();
    }
}

Same error:

Exception in thread "main" java.lang.NoSuchMethodError: scala.math.PartialOrdering.$init$(Lscala/math/PartialOrdering;)V
	at org.economicsl.auctions.PriceOrdering$.<init>(Price.scala:41)
	at org.economicsl.auctions.PriceOrdering$.<clinit>(Price.scala)
	at org.economicsl.auctions.Price$.<init>(Price.scala:27)
	at org.economicsl.auctions.Price$.<clinit>(Price.scala)
	at org.economicsl.auctions.multiunit.SinglePricePoint$.ordering(SinglePricePoint.scala:56)
	at com.bosch.de.AuctionCreator.<init>(AuctionCreator.scala:11)
	at com.bosch.de.JAuctionCreator.createAuction(JAuctionCreator.java:11)
	at com.bosch.de.AuctionTest.<init>(AuctionTest.java:17)
	at com.bosch.de.AuctionTest.main(AuctionTest.java:21)

@davidrpugh
Copy link
Author

@bherd-rb Can you show me the Java code that you used to successfully create an empty four-heap order book?

@bherd-rb
Copy link
Contributor

@davidrpugh In the very first version, I created a simple Scala auction class as follows:

class SimpleAuction {
  var orderBook = FourHeapOrderBook.empty[LimitAskOrder with SingleUnit, LimitBidOrder with SingleUnit]

  def + (order: LimitAskOrder with SingleUnit) = {
    orderBook += order
  }

  def + (order: LimitBidOrder with SingleUnit) = {
    orderBook += order
  }

  def - (order: LimitAskOrder with SingleUnit) = {
    orderBook -= order
  }

  def - (order: LimitBidOrder with SingleUnit) = {
    orderBook -= order
  }

  def clear() = {
    val (pairedOrders, orderBook_new) = orderBook.takeWhileMatched
    orderBook = orderBook_new
    pairedOrders.toList
  }
}

I then created a Java wrapper for that class as follows:

public class JSimpleAuction {
    private SimpleAuction auction = new SimpleAuction();

    public JSimpleAuction() {}

    public void plus(LimitAskOrder order) {
        auction.$plus(order);
    }

    public void plus(LimitBidOrder order) {
        auction.$plus(order);
    }

    public void minus(LimitAskOrder order) {
        auction.$minus(order);
    }

    public void minus(LimitBidOrder order) {
        auction.$minus(order);
    }

    public java.util.List<Tuple2<LimitAskOrder, LimitBidOrder>> clear() {
        List<Tuple2<LimitAskOrder, LimitBidOrder>> matchedOrders = auction.clear();
        return JavaConverters.seqAsJavaListConverter(matchedOrders).asJava();
    }
}

That worked without any problems. I embedded an auction object into a JADE auctioneer and used it to match service providers and consumers continuously.

@davidrpugh
Copy link
Author

@bherd-rb Looks like that was an older order book implementation.

  var orderBook = FourHeapOrderBook.empty[LimitAskOrder with SingleUnit, LimitBidOrder with SingleUnit]

It is no longer necessary to pass the type parameters of the orders when creating the empty order book. Have you been able to create an empty order book using the new syntax? Copied the following from the worksheet...

// Create a four-heap order book and add some orders...
val orderBook = FourHeapOrderBook.empty[Google]
val orderBook2 = orderBook + order3
val orderBook3 = orderBook2 + order4
val orderBook4 = orderBook3 + order9
val orderBook5 = orderBook4 + order8

Also check your import statements. There is a multiunit.LimitAskOrder and a singleunit.LimitAskOrder (similarly for the LimitBidOrder traits). The current implementation of the auction should only work with the singleunit orders.

@bherd-rb
Copy link
Contributor

@davidrpugh I know, that was a very old implementation. In my more recent wrapper (shown above), I'm using the new syntax for the order book.

I have now tried to instantiate just an empty order book (without an enclosing auction) from Java:

FourHeapOrderBook<Service> orderBook = FourHeapOrderBook$.MODULE$.empty(
            SinglePricePoint$.MODULE$.<LimitAskOrder<Service>>ordering(), // this is line 25
            SinglePricePoint$.MODULE$.<LimitBidOrder<Service>>ordering().reverse()
        );

Is the call correct in principle? If I execute that, it gives the same error as before (I have marked line 25 where the exception is thrown in the listing above):

Exception in thread "main" java.lang.NoSuchMethodError: scala.math.PartialOrdering.$init$(Lscala/math/PartialOrdering;)V
	at org.economicsl.auctions.PriceOrdering$.<init>(Price.scala:41)
	at org.economicsl.auctions.PriceOrdering$.<clinit>(Price.scala)
	at org.economicsl.auctions.Price$.<init>(Price.scala:27)
	at org.economicsl.auctions.Price$.<clinit>(Price.scala)
	at org.economicsl.auctions.multiunit.SinglePricePoint$.ordering(SinglePricePoint.scala:56)
	at com.bosch.de.AuctionTest.main(AuctionTest.java:25)

@davidrpugh
Copy link
Author

@bherd-rb Let's try and eliminate the versioning issue. Can you bump your version of Scala to 2.12.1?

@davidrpugh
Copy link
Author

Also, can you push a branch containing your Java code? I am limited in the help that I can provide without having code that I can play with.

@bherd-rb
Copy link
Contributor

@davidrpugh That's what I'm looking into at the moment. I'm not sure if I can switch to a more recent version because updating packages on the Linux VM that I'm working on is restricted by the company. I'll try to upgrade. If it doesn't work, I'll try from home tonight and see if it makes a difference.

And yes -- I'll push the stuff to a separate branch.

@bherd-rb
Copy link
Contributor

@davidrpugh Sorry for the radio silence, I'm drowning in work here at the moment.

I tried to narrow down the problem and executed the test code on my Machine at home with the latest version of the Scala compiler – same effect! This is the simplest possible code to reproduce the problem:

import org.economicsl.auctions.singleunit.*;
import org.economicsl.auctions.singleunit.orderbooks.FourHeapOrderBook;
import org.economicsl.auctions.singleunit.orderbooks.FourHeapOrderBook$

class App{

public static void main( String[] args )
{
  AuctionTest auctionTest = new AuctionTest();
  FourHeapOrderBook<Service> orderBook = FourHeapOrderBook$.MODULE$.empty(
          LimitAskOrder$.MODULE$.<LimitAskOrder<Service>>ordering()
          LimitBidOrder$.MODULE$.<LimitBidOrder<Service>>ordering()
  }
}

When executing that code, it crashes with the error shown further above.

@davidrpugh
Copy link
Author

davidrpugh commented Mar 20, 2017

@bherd-rb

For sake of clarity can you show the exact error for this simplified case? I am very unfamiliar with Java syntax but these lines look strange to me...

LimitAskOrder$.MODULE$.<LimitAskOrder<Service>>ordering()
LimitBidOrder$.MODULE$.<LimitBidOrder<Service>>ordering()

...can the compiler infer the type parameter in this case? This would lead to something like...

LimitAskOrder$.MODULE$.ordering()
LimitBidOrder$.MODULE$.ordering()

...or maybe even passing the type parameter as ...

LimitAskOrder$.MODULE$.ordering<LimitAskOrder<Service>>()
LimitBidOrder$.MODULE$.ordering<LimitBidOrder<Service>>()

...then again the error is a run-time error and not a compile error. So this is probably off base.

@bherd-rb
Copy link
Contributor

@davidrpugh The first option is automatically provided by IntelliJ's code completion. The second option also compiles, but produces the same error at runtime. The third option doesn't compile.

Here is again the error:

Exception in thread "main" java.lang.NoSuchMethodError: scala.math.PartialOrdering.$init$(Lscala/math/PartialOrdering;)V
	at org.economicsl.auctions.PriceOrdering$.<init>(Price.scala:41)
	at org.economicsl.auctions.PriceOrdering$.<clinit>(Price.scala)
	at org.economicsl.auctions.Price$.<init>(Price.scala:27)
	at org.economicsl.auctions.Price$.<clinit>(Price.scala)
	at org.economicsl.auctions.multiunit.SinglePricePoint$.ordering(SinglePricePoint.scala:56)
	at org.economicsl.auctions.singleunit.SingleUnit$.ordering(SingleUnit.scala:42)
	at org.economicsl.auctions.singleunit.LimitAskOrder$.ordering(LimitAskOrder.scala:28)
	at com.bosch.de.AuctionTest.main(AuctionTest.java:23)

I'll keep investigating.

@davidrpugh
Copy link
Author

@bherd-rb How are you compiling the Scala code?

@davidrpugh
Copy link
Author

davidrpugh commented Mar 20, 2017

@bherd-rb When I compile the scala code locally I use SBT as follows...

sbt compile

...from with the auctions directory containing the build.sbt file. Not that in the build.sbt file I am passing a couple of extra options to the compile, specifically the -language:implicitConversions option which when set avoids having to import scala.langauge.implicitConversions in each file where such a conversion occurs. I added this compiler option and removed the explicit import in a previous commit. At present the only file in which an implicit conversion occurs is in the Price.scala file.

On my laptop it seems like IDEA is sometimes (but not always!!) caching such compiler options. I think the following will compile and clean the cache.

sbt clean compile

If you want to double confirm that the compiler is using the new options try running...

sbt clean debug compile

...and search through the cruft that is kicked out for a few lines that look like...

[debug] Calling Scala compiler with arguments  (CompilerInterface):
[debug]         -feature
[debug]         -language:implicitConversions

@davidrpugh
Copy link
Author

@bherd-rb I think that the above might solve the problem because, from the run-time error, it seems like a method that should exist on an object in the core Scala library does not exist. I think this method is dynamically created at compile time when either scala.language.implicitConversions is explicitly imported or the compiler flag is set appropriately (as discussed above).

@davidrpugh
Copy link
Author

@bherd-rb can you push your Java code to a separate branch? I would like to be able to replicate this issue on my local machine.

@bherd-rb
Copy link
Contributor

@davidrpugh I think I solved the problem. But I still have some minor issues. I'll push the stuff and describe what I've done once everything's working correctly.

@davidrpugh
Copy link
Author

@bherd-rb I did a significant refactor of the DoubleAuction.scala file. There is now a base DoubleAuction trait defining the interface for a DoubleAuction the companion object contains two private concrete implementations depending on whether you what an auction with uniform pricing or an auction with discriminatory pricing. Recall that discriminatory price auctions each matched pair of orders is filled at a possibly different price; uniform auctions each matched pair of orders fills at the same "market clearing" price.

Instances are created as follows...

val uniformAuction = DoubleAuction.withUniformPricing[Google]

val discriminatoryAuction = DoubleAuction.withDiscriminatoryPricing[Google]

I made some minor edits to the Java code to fix some minor compilation issues, but have not added code to use the new discriminatory price auction. Let me know what you think!

@bherd-rb
Copy link
Contributor

@davidrpugh Looks good! I will change the Java class accordingly.

@davidrpugh davidrpugh merged commit 0ee8a0d into develop Mar 23, 2017
@davidrpugh davidrpugh deleted the add-double-auction-trait branch April 5, 2017 04:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants