
typequux.Dense.scala Maven / Gradle / Ivy
/**
* Copyright 2019 Harshad Deo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package typequux
import annotation.tailrec
import Comparison.{EQ, GT, LT}
import constraint.TrueConstraint
import Dense._
import language.higherKinds
import language.experimental.macros
import reflect.macros.whitebox.Context
/** Typelevel representation of dense numbers, stored as a list of [[Dense.Digit]]
*
* @author Harshad Deo
* @since 0.1
*/
sealed trait Dense {
/** Lowest priority bit
*
* @group Representation
* @author Harshad Deo
* @since 0.1
*/
type digit <: Digit
/** Rest of the bits, stored in reverse order or priority
*
* @group Representation
* @author Harshad Deo
* @since 0.1
*/
type tail <: Dense
/** Increment the number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Inc <: Dense
/** Decrement the number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Dec <: Dense
/** Add to the number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Add[b <: Dense] <: Dense
/** Multiply with the number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Mult[b <: Dense] = b#Match[Karatsuba[b, DNil], DNil, Dense]
/** Square the number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Sq <: Dense
/** Yoda exponent - to the power of the base, raise the exponent (this is the base).
* Implemented this way for efficiency
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type YodaExp[b <: Dense] = ExpHelper[b, _1] // to the power of two, raise base
/** Unsigned left shift
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type ShiftL <: Dense
/** Unsigned right shift
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type ShiftR <: Dense
/** Typeconstructor for querying whether this is zero
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Match[NonZero <: Up, IfZero <: Up, Up] <: Up
/** Compares with the other dense number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Compare[B <: Dense] = CompareC[B, EQ]
/**
* @author Harshad Deo
* @since 0.1
*/
protected type Len <: Dense
/**
* @author Harshad Deo
* @since 0.1
*/
protected type Karatsuba[x <: Dense, res <: Dense] <: Dense // Karatsuba/Russian Peasant/Egyptian multiplication
/**
* @author Harshad Deo
* @since 0.1
*/
protected type ExpHelper[arg <: Dense, res <: Dense] <: Dense
/**
* @author Harshad Deo
* @since 0.1
*/
protected type CompareC[B <: Dense, Carry <: Comparison] <: Comparison
}
/** Contains implementation for [[Dense]] and typeconstructor aliases that make usage more pleasant
*
* The operations can be shown to satisfy:
*
* 1. Additive commutativity: +[A, B] =:= +[B, A]
*
* 2. Additive associativity: +[A, +[B, C]] =:= +[+[A, B], C]
*
* 3. Additive identity: +[A, _0] =:= A =:= +[_0, A]
*
* 4. Multiplicative commutativity: *[A, B] =:= *[B, A]
*
* 5. Multiplicative associativity: *[A, *[B, C]] =:= *[*[A, B], C]
*
* 6. Multiplicative identity: *[A, _1] =:= A =:= *[_1, A]
*
* 7. Distributivity: *[A, +[B, C]] =:= +[*[A, B], *[A, C]]
*
* 8. Zero exponent: ^[A, _0] =:= _1
*
* 9. One exponent: ^[_1, A] =:= _1
*
* 10. Exponent Identity: ^[A, _1] =:= A
*
* 11. Exponent combination 1: *[^[A, B], ^[A, C]] =:= ^[A, *[B, C]]
*
* 12. Exponent combination 2: ^[^[A, B], C] =:= ^[A, *[B, C]]
*
* 13. Exponent combination 3: ^[*[A, B], C] =:= *[^[A, C], ^[B, C]]
*
* 14. Total Order
*
* @author Harshad Deo
* @since 0.1
*/
object Dense {
/** Represents a digit in the dense encoding of a natural number
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
sealed trait Digit {
/** Typeconstructor for querying whether the digit is zero
*
* @author Harshad Deo
* @since 0.1
*/
type Match[IfOne <: Up, IfZero <: Up, Up] <: Up
/** Typeconstructor to compare two bits
*
* @author Harshad Deo
* @since 0.1
*/
type Compare[D <: Digit] <: Comparison
}
/** Represents a 0 in the dense encoding of a natural number
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
final class D0 extends Digit {
override type Match[IfOne <: Up, IfZero <: Up, Up] = IfZero
override type Compare[D <: Digit] = D#Match[LT, EQ, Comparison]
}
/** Represents a 1 in the dense encoding of a natural number
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
final class D1 extends Digit {
override type Match[IfOne <: Up, IfZero <: Up, Up] = IfOne
override type Compare[D <: Digit] = D#Match[EQ, GT, Comparison]
}
/** Non-zero dense number. The digit is the least significant bit
*
* @tparam d Lowest priority bit
* @tparam T Rest of the bits, in decreasing order of priority
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
final class DCons[d <: Digit, T <: Dense] extends Dense {
override type digit = d
override type tail = T
override type Inc = d#Match[D0 :: T#Inc, D1 :: T, Dense]
override type Dec = d#Match[T#Match[D0 :: T, DNil, Dense], D1 :: T#Dec, Dense]
override type Add[b <: Dense] = b#Match[AddNz[b], d :: T, Dense]
override type Sq = *[d :: T, d :: T]
override type ShiftR = tail
override type ShiftL = D0 :: DCons[d, T]
override type Match[NonZero <: Up, IfZero <: Up, Up] = NonZero
protected type AddNz[b <: Dense] = d#Match[Add1[b], b#digit :: tail#Add[b#tail], Dense]
protected type Add1[b <: Dense] = b#digit#Match[D0 :: tail#Add[b#tail]#Inc, d :: tail#Add[b#tail], Dense]
protected type NewCarry[prev <: Comparison, od <: Digit] = d#Compare[od]#Match[LT, prev, GT, Comparison]
override protected type Karatsuba[x <: Dense, res <: Dense] =
tail#Karatsuba[x#ShiftL, digit#Match[x + res, res, Dense]]
override protected type ExpHelper[arg <: Dense, res <: Dense] =
tail#ExpHelper[arg#Sq, digit#Match[*[res, arg], res, Dense]]
override protected type CompareC[B <: Dense, Carry <: Comparison] =
B#Match[tail#CompareC[B#tail, NewCarry[Carry, B#digit]], GT, Comparison]
override protected type Len = _1 + tail#Len
}
/** Dense Zero
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
final class DNil extends Dense {
override type tail = Nothing
override type digit = Nothing
override type Inc = D1 :: DNil
override type Dec = Nothing
override type Add[b <: Dense] = b
override type Sq = _0
override type ShiftR = DNil
override type ShiftL = DNil
override type Match[NonZero <: Up, IfZero <: Up, Up] = IfZero
override protected type Karatsuba[x <: Dense, res <: Dense] = res
override protected type ExpHelper[arg <: Dense, res <: Dense] = res
override protected type CompareC[B <: Dense, Carry <: Comparison] = B#Match[LT, Carry, Comparison]
override protected type Len = _0
}
/** Builds a new dense number by consing a bit to an existing dense number. The consed bit is the lowest priority
* bit in the resulting number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type ::[H <: Digit, T <: Dense] = DCons[H, T]
/** Alias for adding two dense number
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type +[A <: Dense, B <: Dense] = A#Add[B]
/** Alias for multiplying two dense numbers
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type *[A <: Dense, B <: Dense] = A#Mult[B]
/** Alias for raising the first Dense number to the power of the second
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type ^[A <: Dense, B <: Dense] = B#YodaExp[A]
/** Alias for comparing to dense numbers
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Compare[A <: Dense, B <: Dense] = A#Compare[B]
/** Alias for checking if two dense numbers are equal
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type ===[A <: Dense, B <: Dense] = A#Compare[B]#eq
/** Alias for checking if the first dense number is less than the second
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type <[A <: Dense, B <: Dense] = A#Compare[B]#lt
/** Alias for checking whether the first dense number is less than or equal to the second
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type <=[A <: Dense, B <: Dense] = A#Compare[B]#le
/** Alias for checking whether the first dense number is greater than the second
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type >[A <: Dense, B <: Dense] = A#Compare[B]#gt
/** Alias for checking whether the first dense number is greater than or equal to the second
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type >=[A <: Dense, B <: Dense] = A#Compare[B]#ge
/** Alias for squaring a dense number. Makes the code more pleasant to read
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Sq[A <: Dense] = A#Sq
/** Alias for determing the greatest of two dense numbers
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Max[A <: Dense, B <: Dense] = A#Compare[B]#Match[B, A, A, Dense]
/** Alias for determining the lease of two dense numbers
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
type Min[A <: Dense, B <: Dense] = A#Compare[B]#Match[A, A, B, Dense]
/** Dense 0
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _0 = DNil
/** Dense 1
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _1 = D1 :: DNil
/** Dense 2
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _2 = D0 :: D1 :: DNil
/** Dense 3
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _3 = D1 :: D1 :: DNil
/** Dense 4
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _4 = D0 :: D0 :: D1 :: DNil
/** Dense 5
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _5 = D1 :: D0 :: D1 :: DNil
/** Dense 6
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _6 = D0 :: D1 :: D1 :: DNil
/** Dense 7
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _7 = D1 :: D1 :: D1 :: DNil
/** Dense 8
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _8 = D0 :: D0 :: D0 :: D1 :: DNil
/** Dense 9
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _9 = D1 :: D0 :: D0 :: D1 :: DNil
/** Dense 10
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _10 = D0 :: D1 :: D0 :: D1 :: DNil
/** Dense 11
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _11 = D1 :: D1 :: D0 :: D1 :: DNil
/** Dense 12
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _12 = D0 :: D0 :: D1 :: D1 :: DNil
/** Dense 13
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _13 = D1 :: D0 :: D1 :: D1 :: DNil
/** Dense 14
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _14 = D0 :: D1 :: D1 :: D1 :: DNil
/** Dense 15
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _15 = D1 :: D1 :: D1 :: D1 :: DNil
/** Dense 16
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _16 = D0 :: D0 :: D0 :: D0 :: D1 :: DNil
/** Dense 17
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _17 = D1 :: D0 :: D0 :: D0 :: D1 :: DNil
/** Dense 18
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _18 = D0 :: D1 :: D0 :: D0 :: D1 :: DNil
/** Dense 19
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _19 = D1 :: D1 :: D0 :: D0 :: D1 :: DNil
/** Dense 20
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _20 = D0 :: D0 :: D1 :: D0 :: D1 :: DNil
/** Dense 21
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _21 = D1 :: D0 :: D1 :: D0 :: D1 :: DNil
/** Dense 22
*
* @group Number aliases
* @author Harshad Deo
* @since 0.1
*/
type _22 = D0 :: D1 :: D1 :: D0 :: D1 :: DNil
/** Builds a value level [[scala.Long]] representation of a dense type.
*
* @tparam D Type to be converted to a value
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
final class DenseRep[D <: Dense](val v: Long) extends AnyVal
/** Contains implicit definitions to build the value level representation of a dense type as a [[scala.Long]]
*
* @group Implementation
* @author Harshad Deo
* @since 0.1
*/
object DenseRep {
/** Builds an instance of [[DenseRep]] by delegating to the macro
*
* @tparam D The Dense type to be converted
*
* @author Harshad Deo
* @since 0.6.4
*/
implicit def build[D <: Dense]: DenseRep[D] = macro buildImpl[D]
def buildImpl[D <: Dense](c: Context)(wtt: c.WeakTypeTag[D]): c.Tree = {
import c.universe._
def processType(tp: Type) = tp match {
case z: TypeRef => z.dealias
case _ => tp
}
def allTypes(xs: List[Type]): List[Type] = xs match {
case a :: b :: Nil => a :: allTypes(processType(b).typeArgs)
case _ => Nil
}
val d0ref = implicitly[c.WeakTypeTag[Dense.D0]].tpe
val d1ref = implicitly[c.WeakTypeTag[Dense.D1]].tpe
@tailrec
def go(pending: List[Type], acc: Long, addn: Long): c.Tree = pending match {
case h :: t =>
if (h =:= d0ref) {
go(t, acc, addn << 1)
} else if (h =:= d1ref) {
go(t, acc | addn, addn << 1)
} else {
c.abort(c.enclosingPosition, s"DenseRep cannot be materialized for ${show(wtt.tpe)}")
}
case Nil => q"new typequux.Dense.DenseRep[${wtt.tpe}]($acc)"
}
go(allTypes(processType(wtt.tpe).typeArgs), 0, 1)
}
}
/** Builds a value level [[scala.Int]] representation of a dense type
*
* @tparam D Type to be converted to a value
*
* @group Implementation
* @author Harshad Deo
* @since 0.3.1
*/
final class DenseIntRep[D](val v: Int) extends AnyVal
/** Contains implicit definitional to build a value level representation of a dense type as a [[scala.Int]]
*
* @group Implementation
* @author Harshad Deo
* @since 0.3.1
*/
object DenseIntRep {
/** Builds an instance of [[DenseIntRep]] by delegating to the macro
*
* @tparam D The Dense type to be converted
*
* @author Harshad Deo
* @since 0.6.4
*/
implicit def build[D <: Dense]: DenseIntRep[D] = macro buildImpl[D]
@SuppressWarnings(Array("org.wartremover.warts.Any"))
def buildImpl[D <: Dense](c: Context)(wtt: c.WeakTypeTag[D]): c.Tree = {
import c.universe._
def processType(tp: Type) = tp match {
case z: TypeRef => z.dealias
case _ => tp
}
def allTypes(xs: List[Type]): List[Type] = xs match {
case a :: b :: Nil => a :: allTypes(processType(b).typeArgs)
case _ => Nil
}
val proc = processType(wtt.tpe)
val dnilRef = implicitly[c.WeakTypeTag[Dense.DNil]].tpe
val dconsRef = implicitly[c.WeakTypeTag[Dense.DCons[_, _]]].tpe
if (proc =:= dnilRef) {
q"new typequux.Dense.DenseIntRep[${wtt.tpe}](0)"
} else if (proc <:< dconsRef) {
val d0ref = implicitly[c.WeakTypeTag[Dense.D0]].tpe
val d1ref = implicitly[c.WeakTypeTag[Dense.D1]].tpe
@tailrec
def go(pending: List[Type], acc: Int, addn: Int): c.Tree = pending match {
case h :: t =>
if (h =:= d0ref) {
go(t, acc, addn << 1)
} else if (h =:= d1ref) {
go(t, acc | addn, addn << 1)
} else {
c.abort(c.enclosingPosition, s"DenseIntRep cannot be materialized for ${show(wtt.tpe)}")
}
case Nil => q"new typequux.Dense.DenseIntRep[${wtt.tpe}]($acc)"
}
go(allTypes(proc.typeArgs), 0, 1)
} else {
c.abort(c.enclosingPosition, s"DenseIntRep cannot be materialized for ${show(wtt.tpe)}")
}
}
}
/** Builds value level representation of a [[Dense]] as a [[scala.Long]]
*
* @tparam D Dense type to be converted to a value
*
* @group Operations
* @author Harshad Deo
* @since 0.1
*/
def toLong[D <: Dense](implicit dr: DenseRep[D]): Long = dr.v
/** Builds value level representation of a [[Dense]] as a [[scala.Int]]
*
* @tparam D Dense type to be converted to a value
*
* @group Operations
* @author Harshad Deo
* @since 0.3.1
*/
def toInt[D <: Dense](implicit dr: DenseIntRep[D]): Int = dr.v
}
/** Marker trait for typelevel subtraction of [[Dense]] numbers.
*
* Takes linear time (compared to log time for addition), therefore its usage should be limited
*
* @tparam M Minuend
* @tparam S Subtrahend
* @tparam D Difference
*
* @author Harshad Deo
* @since 0.1
*/
sealed trait DenseDiff[M, S, D]
/** Contains implicit definitions to build a [[DenseDiff]] marker
*
* @author Harshad Deo
* @since 0.1
*/
object DenseDiff {
/** Base case for [[DenseDiff]]
*
* @tparam M Minuend
*
* @author Harshad Deo
* @since 0.1
*/
implicit def dsr0[M <: Dense]: DenseDiff[M, _0, M] = new DenseDiff[M, _0, M] {}
/** Induction case for [[DenseDiff]]
*
* @tparam M Minuend
* @tparam S Subtrahend
* @tparam DP Difference
*
* @author Harshad Deo
* @since 0.1
*/
implicit def dsrN[M <: Dense, S <: Dense, DP <: Dense](implicit ev: DenseDiff[M#Dec, S#Dec, DP],
ev1: TrueConstraint[>[S, _0]]): DenseDiff[M, S, DP] =
new DenseDiff[M, S, DP] {}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy