diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/ExtensibleVisitor.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/ExtensibleVisitor.scala index 5695d559..c4d10a21 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/ExtensibleVisitor.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/ExtensibleVisitor.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.approach.oo - -/*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.{TestCase, TypeRep, Command, NameProvider, AbstractSyntax, Understands} import Command.Generator import org.combinators.cogen.paradigm.{AddImport, AnyParadigm, FindClass, Generics, ObjectOriented, ParametricPolymorphism, ResolveImport} @@ -99,7 +97,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { _ <- addTypeParameter(visitTyParam, Command.skip) // this returns mangled visitTypeParameter name and gets list of all type parameters, for which there is only one, so we get head - args <- getTypeArguments() + args <- getTypeArguments _ <- setReturnType(args.head) // identify Visitor @@ -178,7 +176,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { } /** - * Creates the signature for the 'abstract R visit(DataType exp)' method which still has no body, and can + * Creates the signature for the 'abstract R visit(DataType exp)' method which still has no code body, and can * thus become an abstract interface declaration or form the basis for an implementation. * * {{{ @@ -390,7 +388,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { * Compute the name for the visitor interface of the given model, if a new interface is required. * * Base remains as {visitorClass} - * sub-classes are {visitorClass}DataTypes... + * subclasses are {visitorClass}DataTypes... */ def visitorInterfaceName(model: GenericModel): Seq[Name] = { if (model.isDomainBase) { @@ -428,7 +426,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { vType = visitorInterfaceName(model) // convert Name to a class visitorClassType <- findClass(vType *) - tpeParam <- getTypeArguments() + tpeParam <- getTypeArguments instVisitClassType <- applyType(visitorClassType, tpeParam) castV <- castObject(instVisitClassType, v) // invoke visit method on 'v' with 'this' as argument @@ -517,7 +515,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { } yield () } - /** Take existing visitor generated by Shared and add (where needed) a "extends VisitorSub" + /** Take existing visitor generated by Shared and add (where needed) "extends VisitorSub" * * @param domain create visitor interface for the given model in the extension graph. * @return @@ -767,7 +765,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { val modelToUse = modelsToUse.head /** - * There is special case in k1 for MultBy, which needs a makeEval factory method but it isn't overridden + * There is special case in k1 for MultBy, which needs a makeEval factory method, but it isn't overridden * because it is a dependent operation and appears for the first time. * * makeIsNeg in the Eql.java file in j3 DOES NOT override because it is first presence. Fix this by @@ -775,7 +773,7 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { * in modelToUse so they cannot be overridden. DONE * * Harder one is k1.MultBy which has a dependent operation Eval, but ONLY for the first time in K1 and - * no one before. IN Java if this is public without @Override annotation it works OK. However in Scala + * no one before. IN Java if this is public without @Override annotation it works OK. However, in Scala * there truly needs to be the "override" keyword. * * Final one is a result of single inheritance. Once k2j6 decides to extend from j3 branch, methods that @@ -821,10 +819,10 @@ trait ExtensibleVisitor extends SharedOO with OperationAsClass { // ever happens, logic like above could be used, though .filter (p => p.beforeOrEqual(primaryParent.get)).head n = n.former.head } - exists_in_past // if exists in past, then must override + exists_in_past // if exists in the past, then must override } } else { - // for O1 need to double check modelToUse != domain since means parent exists + // for O1 need to double-check modelToUse != domain since means parent exists (!modelToUse.ops.contains(operation)) || (modelToUse != domain) // if same COULD be defining, but only if previously defined } diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/Interpreter.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/Interpreter.scala index a0c6dd83..8f5dc205 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/Interpreter.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/Interpreter.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.approach.oo - -/*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.{Command, TestCase, TypeRep, Understands, NameProvider, AbstractSyntax} import Command.Generator @@ -186,7 +184,7 @@ sealed trait Interpreter extends SharedOO { for { _ <- setInterface() - // former merge points need to be included, so past.lastModelWithOperation) is changed to below. Make + // former merge points need to be included, so past.lastModelWithOperation is changed to below. Make // sure to 'distinct' these models to avoid adding same interface multiple time (can happen with 3-way merge) _ <- forEach(domain.former.map(past => latestModelDefiningNewTypeInterface(past)).distinct) { m => for { @@ -286,9 +284,6 @@ sealed trait Interpreter extends SharedOO { /** * Access attributes using default getter methods. - * - * @param attribute Data Type Case attribute to be accessed - * @return */ def attributeInterpreterAccess(att: Attribute, tpeCase: DataTypeCase, domain: GenericModel, baseType: Option[paradigm.syntax.Type]): Generator[MethodBodyContext, Expression] = { import ooParadigm.methodBodyCapabilities._ @@ -361,7 +356,7 @@ sealed trait Interpreter extends SharedOO { } } - // add a parent IF type defined earlier, in ANY of its formers.. + // add a parent IF type defined earlier, in ANY of its formers. def shouldAddParent: Boolean = { model.former.exists(m => m.findTypeCase(tpeCase).isDefined) } diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/ObjectAlgebras.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/ObjectAlgebras.scala index c8399427..9c3ad371 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/ObjectAlgebras.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/ObjectAlgebras.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.approach.oo - -/*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.{TestCase, TypeRep, Command, Understands, NameProvider, AbstractSyntax} import Command.Generator diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/RuntimeDispatch.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/RuntimeDispatch.scala index 46337924..3ae6aeb6 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/RuntimeDispatch.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/RuntimeDispatch.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.approach.oo /*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.paradigm.AnyParadigm.syntax._ @@ -18,7 +18,7 @@ import org.combinators.ep.domain.extensions._ * Runtime Dispatch * * Have to decide whether to use side effects or Generics. This current implementation uses the Visitor generics - * approach, which can be adopted by different object oriented languages. + * approach, which can be adopted by different object-oriented languages. */ trait RuntimeDispatch extends SharedOO with OperationAsClass { val paradigm: AnyParadigm @@ -125,7 +125,7 @@ trait RuntimeDispatch extends SharedOO with OperationAsClass { */ def makeDispatchingOperation(model: GenericModel, op: Operation): Generator[ClassContext, Unit] = { def ifStmt(): Generator[MethodBodyContext, Option[Expression]] = { - import exceptions.exceptionCapabilities._ + import exceptions.exceptionsCapabilities._ import impParadigm.imperativeCapabilities._ import ooParadigm.methodBodyCapabilities._ import paradigm.methodBodyCapabilities._ diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/SharedOO.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/SharedOO.scala index 791e2814..d44c091d 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/SharedOO.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/SharedOO.scala @@ -388,7 +388,7 @@ trait SharedOO extends ApproachImplementationProvider { } /** - * Make a single getter method for the 'att' attribute which only has signature, and no body. + * Make a single getter method for the 'att' attribute which only has signature, and no code body. * * The following example is for the 'Right' attribute where the type is mapped to Exp * {{{ diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/Traditional.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/Traditional.scala index 553c1191..bbbac689 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/Traditional.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/Traditional.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.approach.oo - -/*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.{Command, NameProvider, AbstractSyntax} import Command.Generator diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/TriviallyClean.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/TriviallyClean.scala index 9ac28c51..d5873b31 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/TriviallyClean.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/TriviallyClean.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.approach.oo - -/*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.{TestCase, TypeRep, Command, NameProvider, AbstractSyntax, Understands} import org.combinators.cogen.paradigm.{AddImport, AnyParadigm, FindClass, ObjectOriented, ResolveImport} diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/Visitor.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/Visitor.scala index c7538966..3e4ef9d4 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/Visitor.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/Visitor.scala @@ -238,7 +238,7 @@ trait Visitor extends SharedOO with OperationAsClass { self => _ <- addTypeParameter(visitTyParam, Command.skip) // this returns mangled visitTypeParameter name and gets list of all type parameters, for which there is only one, so we get head - args <- getTypeArguments() + args <- getTypeArguments _ <- setReturnType(args.head) // identify Visitor @@ -641,7 +641,7 @@ trait Visitor extends SharedOO with OperationAsClass { self => } /** - * Creates the signature for the 'abstract R visit(DataType exp)' method which still has no body, and can + * Creates the signature for the 'abstract R visit(DataType exp)' method which still has no code body, and can * thus become an abstract interface declaration or form the basis for an implementation. * * {{{ @@ -755,7 +755,7 @@ trait Visitor extends SharedOO with OperationAsClass { self => _ <- addClassToProject(visitorSpecifics.makeVisitorInterface(flatDomain.typeCases.distinct), visitorClass) // Figure out which model to use for this operation so it aligns with EIPS. In fact, sending flatDomain is exactly wrong - // if two predecessors (and cannot decide which one to take) then we are in charge otherwise we pick one branch that has latest one + // if two predecessors (and cannot decide which one to take) then we are in charge otherwise we pick one branch that has the latest one _ <- forEach (flatDomain.ops) { op => { addClassToProject(visitorSpecifics.makeOperationImplementation(gdomain, op, domainSpecific), names.mangle(names.conceptNameOf(op))) } diff --git a/approach/src/main/scala/org/combinators/ep/approach/oo/Visualize.scala b/approach/src/main/scala/org/combinators/ep/approach/oo/Visualize.scala index 65e5e00e..82af003c 100644 --- a/approach/src/main/scala/org/combinators/ep/approach/oo/Visualize.scala +++ b/approach/src/main/scala/org/combinators/ep/approach/oo/Visualize.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.approach.oo - -/*DI:LI:AD*/ +package org.combinators.ep.approach.oo /*DI:LI:AD*/ import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} import org.combinators.ep.domain.{GenericModel, GraphViz} @@ -20,7 +18,7 @@ import org.combinators.ep.domain.extensions._ * https://dreampuf.github.io/GraphvizOnline * * Choose "graphviz" as the approach and (for either Java or Scala) generate the resulting - * code. What it does, instead, is generate the OO solution and then creates files, either + * code. What it does, instead, is to generate the OO solution and then creates files, either * "eip.viz" (structural evolution) or "evolution.viz" (which also includes dependency links) * that you can copy and paste into the above service. */ diff --git a/attic/language/cpp/src/main/scala/org/combinators/ep/language/cpp/CPP.scala b/attic/language/cpp/src/main/scala/org/combinators/ep/language/cpp/CPP.scala index 57104ac9..845c4134 100644 --- a/attic/language/cpp/src/main/scala/org/combinators/ep/language/cpp/CPP.scala +++ b/attic/language/cpp/src/main/scala/org/combinators/ep/language/cpp/CPP.scala @@ -162,7 +162,7 @@ final class CPPClass (val _name:String, _signature:String, val _publicArea:Seq[C val name:String = _name val signature:String = _signature val publicArea:Seq[CPPElement] = _publicArea - val privateArea:Seq[CPPElement] = _privateArea + val privateArea:Seq[CPPElement] = _privateArea var superClass : String = "" override def fileName:String = name diff --git a/attic/language/gj/src/main/scala/org/combinators/ep/language/gj/WadlerGenerator.scala b/attic/language/gj/src/main/scala/org/combinators/ep/language/gj/WadlerGenerator.scala index a5bf1ec0..d5b446ff 100644 --- a/attic/language/gj/src/main/scala/org/combinators/ep/language/gj/WadlerGenerator.scala +++ b/attic/language/gj/src/main/scala/org/combinators/ep/language/gj/WadlerGenerator.scala @@ -85,7 +85,7 @@ trait WadlerGenerator extends GJGenerator { // base will be assumed to have at least one datatype exp and one e val baseMethods = model.types.map(exp => { - val params:String = exp.attributes.map(att => GJ(s"${typeConverter(att.tpe)} ${att.instance}")).mkString(",") + val params:String = exp.attributes.map(att => GJ(s"${typeConverter(att.tpe)} ${att.instance}")).mkString(",") GJ(s"public R for${exp.concept}($params);") }) @@ -116,7 +116,7 @@ trait WadlerGenerator extends GJGenerator { def generateBase(base:Model): Seq[GJWithPath] = { // base will be assumed to have at least one datatype exp and one e val baseMethods = base.types.map(exp => { - val params:String = exp.attributes.map(att => GJ(s"${typeConverter(att.tpe)} ${att.instance}")).mkString(",") + val params:String = exp.attributes.map(att => GJ(s"${typeConverter(att.tpe)} ${att.instance}")).mkString(",") GJ(s"public R for${exp.concept}($params);") }) diff --git a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/HaskellGenerator.scala b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/HaskellGenerator.scala index 381300da..14d574b3 100644 --- a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/HaskellGenerator.scala +++ b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/HaskellGenerator.scala @@ -90,7 +90,7 @@ trait HaskellGenerator extends DomainIndependentGenerator with StandardHaskellBi Haskell(s"${exp.concept} $list") // not sure how much this is needed }).mkString(" | ") - val binaryTreeInterface = if (m.flatten().hasBinaryMethod) { + val binaryTreeInterface = if (m.flatten().hasBinaryMethod) { // astree method declaration definedDataSubTypes("", m.types) ++ declarations } else { diff --git a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/alacarte/ALaCarteTestGenerator.scala b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/alacarte/ALaCarteTestGenerator.scala index f5205d0c..24e9e732 100644 --- a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/alacarte/ALaCarteTestGenerator.scala +++ b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/alacarte/ALaCarteTestGenerator.scala @@ -86,7 +86,7 @@ trait ALaCarteTestGenerator extends HUnitTestGenerator { Haskell(s"${exp.concept}T $list") // not sure how much this is needed }).mkString(" | ") - val binaryTreeInterface = if (m.flatten().hasBinaryMethod) { + val binaryTreeInterface = if (m.flatten().hasBinaryMethod) { // astree method declaration definedDataSubTypes("", m.types) ++ declarations } else { diff --git a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/e6.scala b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/e6.scala index aff14278..ab9c43c8 100644 --- a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/e6.scala +++ b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/e6.scala @@ -56,7 +56,7 @@ trait e6 extends Evolution with HaskellGenerator with HUnitTestGenerator with M0 case Equals => exp match { case Lit => - val value2 = Haskell(expression(exp, litValue).getCode + "2") + val value2 = Haskell(expression(exp, litValue).getCode + "2") result(Haskell(s" ${expression(exp, litValue)} == $value2 ")) case u:Unary => diff --git a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/grow/GrowGenerator.scala b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/grow/GrowGenerator.scala index 7cd6e0c2..19f9e1a9 100644 --- a/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/grow/GrowGenerator.scala +++ b/attic/language/haskell/src/main/scala/org/combinators/ep/language/haskell/grow/GrowGenerator.scala @@ -669,7 +669,7 @@ trait GrowGenerator extends HaskellGenerator with StandardHaskellBinaryMethod wi * @return */ override def generateDataTypes(m:domain.Model): HaskellWithPath = { - val binaryTreeInterface = if (m.flatten().hasBinaryMethod) { + val binaryTreeInterface = if (m.flatten().hasBinaryMethod) { definedDataSubTypes("", m.types) ++ declarations } else { Seq.empty diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/CodeGenerator.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/CodeGenerator.scala index 0e5683ed..f168f79b 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/CodeGenerator.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/CodeGenerator.scala @@ -1,7 +1,7 @@ package org.combinators.ep.language.scala /*DI:LD:AI*/ import cats.{Apply => _} -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command //import org.combinators.ep.generator.paradigm.{Generics, ParametricPolymorphism} import org.combinators.ep.language.scala.paradigm._ diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/ContextSpecificResolver.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/ContextSpecificResolver.scala index 0d6f745a..7fda6015 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/ContextSpecificResolver.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/ContextSpecificResolver.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.domain.instances.InstanceRep import org.combinators.ep.generator.Command import org.combinators.ep.generator.Command.Generator diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/Main.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/Main.scala index f70fb2d6..4b1e08d6 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/Main.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/Main.scala @@ -81,7 +81,7 @@ class Main { generator.doublesInMethod, generator.booleansInMethod, generator.equalityInMethod) - val m8_eip = eips.M8.imperative[approach.paradigm.type,ApproachImplementationProvider.WithParadigm](approach.paradigm)(m7i2_eip)( + val m8_eip = eips.M8.imperative[approach.paradigm.type,ApproachImplementationProvider.WithParadigm](approach.paradigm)(m7i2_eip)( generator.imperativeInMethod, generator.doublesInMethod, generator.booleansInMethod, diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/AnyParadigm.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/AnyParadigm.scala index b61955ac..64d8bf50 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/AnyParadigm.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/AnyParadigm.scala @@ -3,7 +3,7 @@ package org.combinators.ep.language.scala.paradigm /*DI:LD:AI*/ import java.nio.file.{Path, Paths} import scala.meta._ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.domain.instances.InstanceRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.{Command, FileWithPath, Understands} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/Functional.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/Functional.scala index 8fc84380..fbb806a7 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/Functional.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/Functional.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.paradigm.{AddImport, AddMethod, AddType, AddTypeConstructor, AddTypeLookup, FindMethod, FindType, InstantiateType, ResolveImport, ToTargetLanguageType, Functional => Func} import org.combinators.ep.language.scala.{Syntax, TypeCtxt, _} import org.combinators.ep.generator.Understands diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ObjectOriented.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ObjectOriented.scala index d4dda0ff..47975ea3 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ObjectOriented.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ObjectOriented.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.domain.instances.InstanceRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.{Command, Understands} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Arithmetic.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Arithmetic.scala index 5085a6a2..4c253a5a 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Arithmetic.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Arithmetic.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.Understands import org.combinators.ep.generator.paradigm.Apply diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Assertions.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Assertions.scala index 3a125a99..b02d0eef 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Assertions.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Assertions.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.{Command, Understands} import org.combinators.ep.generator.paradigm.{Apply, Functional} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Booleans.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Booleans.scala index 17e044dd..42a8e5a3 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Booleans.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Booleans.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.Understands import org.combinators.ep.generator.paradigm.Apply diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Equality.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Equality.scala index 71c25874..438ca9c4 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Equality.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Equality.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.{Command, Understands} import org.combinators.ep.generator.paradigm.{Apply, GetMember} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Lists.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Lists.scala index 75854643..82df975b 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Lists.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Lists.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.domain.instances.InstanceRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.{Command, Understands} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/RealArithmetic.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/RealArithmetic.scala index 10989069..b22729b3 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/RealArithmetic.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/RealArithmetic.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.paradigm.Apply import org.combinators.ep.generator.paradigm.ffi.{Abs, Cos, EulersNumber, Floor, Log, Pi, Pow, Sin, Sqrt, RealArithmetic => RArith} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Strings.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Strings.scala index 9a6ed048..c915e92f 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Strings.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Strings.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.generator.Command.Generator import org.combinators.ep.generator.{Command, Understands} import org.combinators.ep.generator.paradigm.{Apply, GetMember} diff --git a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Trees.scala b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Trees.scala index 90000c78..1bc08ee7 100644 --- a/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Trees.scala +++ b/attic/language/scala/src/main/scala/org/combinators/ep/language/scala/paradigm/ffi/Trees.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.scala.paradigm.ffi /*DI:LD:AI*/ -import org.combinators.ep.domain.abstractions.TypeRep +import org.combinators.cogen.TypeRep import org.combinators.ep.domain.instances.InstanceRep import org.combinators.ep.domain.tree.{Leaf, Node} import org.combinators.ep.generator.Command.Generator diff --git a/attic/oldjava/TestGenerator.scala b/attic/oldjava/TestGenerator.scala index af3c7697..f248c97a 100644 --- a/attic/oldjava/TestGenerator.scala +++ b/attic/oldjava/TestGenerator.scala @@ -3,7 +3,7 @@ package org.combinators.ep.language.java /*DI:LD:AI*/ import com.github.javaparser.ast.body.MethodDeclaration import org.combinators.ep.domain.abstractions._ import org.combinators.ep.domain.instances._ -//import org.combinators.ep.generator.DomainIndependentTestGenerator +//import org.combinators.cogen.DomainIndependentTestGenerator import org.combinators.templating.twirl.Java abstract class TestGenerator (val gen:DomainIndependentJavaGenerator) { // }, independentTestGen: DomainIndependentTestGenerator) { diff --git a/attic/oldjava/algebra/AlgebraGenerator.scala b/attic/oldjava/algebra/AlgebraGenerator.scala index 7e57cdd9..91992ba8 100644 --- a/attic/oldjava/algebra/AlgebraGenerator.scala +++ b/attic/oldjava/algebra/AlgebraGenerator.scala @@ -393,7 +393,7 @@ trait AlgebraGenerator extends DomainIndependentJavaGenerator { // FIX ME FIX ME // }) // val cons:Seq[Statement] = exp.attributes.flatMap(att => Java(s" this.${att.instance} = ${att.instance};").statements()) // -// val constructor = s"""|public ${exp.concept} (${params.mkString(",")}) { +// val constructor = s"""|public ${exp.concept} (${params.mkString(",")}) { // | ${cons.mkString("\n")} // |}""".stripMargin // val unit = Java(s"""|package algebra.oo; diff --git a/attic/oldjava/algebra/AlgebraTestGenerator.scala b/attic/oldjava/algebra/AlgebraTestGenerator.scala index 2a0699c7..35e3143a 100644 --- a/attic/oldjava/algebra/AlgebraTestGenerator.scala +++ b/attic/oldjava/algebra/AlgebraTestGenerator.scala @@ -2,7 +2,7 @@ package org.combinators.ep.language.java.algebra /*DI:LD:AD*/ import com.github.javaparser.ast.body.{FieldDeclaration, MethodDeclaration} //import org.combinators.ep.domain.BaseDomain -//import org.combinators.ep.generator.DomainIndependentTestGenerator +//import org.combinators.cogen.DomainIndependentTestGenerator import org.combinators.ep.language.java.{JUnitTestGenerator, JavaBinaryMethod, DomainIndependentJavaGenerator} import org.combinators.templating.twirl.Java diff --git a/attic/oldjava/extensibleVisitor/ExtensibleVisitorGenerator.scala b/attic/oldjava/extensibleVisitor/ExtensibleVisitorGenerator.scala index c7d3b06e..b9995bab 100644 --- a/attic/oldjava/extensibleVisitor/ExtensibleVisitorGenerator.scala +++ b/attic/oldjava/extensibleVisitor/ExtensibleVisitorGenerator.scala @@ -3,7 +3,7 @@ package org.combinators.ep.language.java.extensibleVisitor /*DI:LD:AD*/ import com.github.javaparser.ast.body.{ConstructorDeclaration, MethodDeclaration, TypeDeclaration} //import org.combinators.ep.domain.BaseDomain import org.combinators.ep.domain.abstractions.Operation -//import org.combinators.ep.generator.OperationDependency +//import org.combinators.cogen.OperationDependency import org.combinators.ep.language.java.JavaNameProvider.mangle import org.combinators.ep.language.java.JavaSyntax.Statement import org.combinators.ep.language.java.visitor.VisitorGenerator diff --git a/attic/oldjava/interpreter/InterpreterTestGenerator.scala b/attic/oldjava/interpreter/InterpreterTestGenerator.scala index a9bab65f..297dffbb 100644 --- a/attic/oldjava/interpreter/InterpreterTestGenerator.scala +++ b/attic/oldjava/interpreter/InterpreterTestGenerator.scala @@ -1,7 +1,7 @@ package org.combinators.ep.language.java.interpreter /*DI:LD:AD*/ //import org.combinators.ep.domain.BaseDomain -//import org.combinators.ep.generator.DomainIndependentTestGenerator +//import org.combinators.cogen.DomainIndependentTestGenerator import org.combinators.ep.language.java.{JUnitTestGenerator, DomainIndependentJavaGenerator} import org.combinators.templating.twirl.Java diff --git a/build.sbt b/build.sbt index 0ae8152e..fe164884 100644 --- a/build.sbt +++ b/build.sbt @@ -130,6 +130,19 @@ lazy val helloWorldProject: Project = ) .dependsOn(cogen, languageJava, languageNewScala) +// first update general infra. for FFI +// second update java code gener updates +// third then in-between +// fourth then newScala +lazy val dynamicProgramming: Project = + (Project(id = s"dynamicProgramming", base = file(s"dynamicProgramming"))) + .settings(commonSettings: _*) + .settings(noPublishSettings: _*) + .settings( + moduleName := s"expression-problem-language-dynamic-programming", + ) + .dependsOn(cogen, languageJava, languageNewScala) + lazy val languageInbetween = standardLanguageProject("inbetween") diff --git a/builder/src/main/scala/org/combinators/ep/builder/java/CodeGenerator.scala b/builder/src/main/scala/org/combinators/ep/builder/java/CodeGenerator.scala index 78823673..472cca9b 100644 --- a/builder/src/main/scala/org/combinators/ep/builder/java/CodeGenerator.scala +++ b/builder/src/main/scala/org/combinators/ep/builder/java/CodeGenerator.scala @@ -1,7 +1,5 @@ -package org.combinators.ep.builder.java +package org.combinators.ep.builder.java /*DI:LD:AI*/ -import com.github.javaparser.ast.PackageDeclaration -import org.combinators.cogen.Command import org.combinators.ep.builder.java.paradigm.ffi.Trees import org.combinators.ep.language.java.{Config, CtorCtxt, MethodBodyCtxt} import org.combinators.ep.language.java.paradigm.ObjectOriented diff --git a/builder/src/main/scala/org/combinators/ep/builder/java/Main.scala b/builder/src/main/scala/org/combinators/ep/builder/java/Main.scala index 506899b5..88659a40 100644 --- a/builder/src/main/scala/org/combinators/ep/builder/java/Main.scala +++ b/builder/src/main/scala/org/combinators/ep/builder/java/Main.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.builder.java - -/*DD:LD:AD*/ +package org.combinators.ep.builder.java /*DD:LD:AD*/ /** * 1. To generate a single approach for a single stage in an Extension Graph, see [[DirectToDiskMain]] @@ -577,8 +575,6 @@ object GenerateAllForOneApproach extends IOApp { object QuickValidation extends Subselection { - - // note that visitorSideEffect and dispatch are omitted from this validation. VISITORSIDEEFFECT has a problem // with the test cases in that the methods become too long for the JavaVM and attempts to subdivide them fail // because visitorSideEffect needs to create visitor objects, and arbitrarily splitting test cases means that @@ -595,12 +591,9 @@ object QuickValidation extends Subselection { // latest in all system families val evolutions = Seq("M9", "J8", "A3", "O1OA", "OD3", "OO3", "V1", "D3", "I2M3I1N1", "O2") - } object GenerateAllMain extends Subselection { - - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { @@ -613,12 +606,9 @@ object GenerateAllMain extends Subselection { } val evolutions = Seq("M0", "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M7I2", "M8", "M9", "I1", "A1", "A1M3", "A1M3I2", "A3", "I2", "O1", "O2", "OA", "O1OA", "OD1", "OD2", "OD3", "OO1", "OO2", "OO3") - } object GenerateAllJ extends Subselection { - - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { @@ -630,11 +620,9 @@ object GenerateAllJ extends Subselection { args.head } val evolutions = Seq("M0", "J1", "J2", "J3", "K1", "K2", "J4", "J5", "J6", "K2J6", "J7", "J8") - } object GenerateAllD1D2 extends Subselection { - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { @@ -649,7 +637,6 @@ object GenerateAllD1D2 extends Subselection { } object GenerateAllMerging extends Subselection { - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { @@ -664,8 +651,6 @@ object GenerateAllMerging extends Subselection { } object GenerateAllExtended extends Subselection { - - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { @@ -680,8 +665,6 @@ object GenerateAllExtended extends Subselection { } object GenerateAllThirdAlternate extends Subselection { - - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { @@ -696,8 +679,6 @@ object GenerateAllThirdAlternate extends Subselection { } object GenerateShapes extends Subselection { - - def approaches(args: List[String]): Seq[String] = if (args.isEmpty) { Seq("oo", "visitor", "extensibleVisitor", "interpreter", "coco", "trivially", "algebra") } else { diff --git a/builder/src/main/scala/org/combinators/ep/builder/java/paradigm/ffi/Trees.scala b/builder/src/main/scala/org/combinators/ep/builder/java/paradigm/ffi/Trees.scala index a7a86325..87d0dd96 100644 --- a/builder/src/main/scala/org/combinators/ep/builder/java/paradigm/ffi/Trees.scala +++ b/builder/src/main/scala/org/combinators/ep/builder/java/paradigm/ffi/Trees.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.builder.java.paradigm.ffi - -/*DI:LD:AI*/ +package org.combinators.ep.builder.java.paradigm.ffi /*DI:LD:AI*/ import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.`type`.Type @@ -15,7 +13,7 @@ import org.combinators.ep.domain.abstractions.DomainTpeRep import org.combinators.ep.domain.tree.{Leaf, Node} import org.combinators.ep.language.java.CodeGenerator.Enable import org.combinators.ep.language.java.Syntax.default.* -import org.combinators.ep.language.java.paradigm.{AnyParadigm, Generics, ObjectOriented} +import org.combinators.ep.language.java.paradigm.{AnyParadigm, ObjectOriented} import org.combinators.ep.language.java.{ContextSpecificResolver, ProjectCtxt} trait Trees[Ctxt, AP <: AnyParadigm] extends Ts[Ctxt] { diff --git a/builder/src/main/scala/org/combinators/ep/builder/scala/CodeGenerator.scala b/builder/src/main/scala/org/combinators/ep/builder/scala/CodeGenerator.scala deleted file mode 100644 index 823d0dbf..00000000 --- a/builder/src/main/scala/org/combinators/ep/builder/scala/CodeGenerator.scala +++ /dev/null @@ -1,22 +0,0 @@ -package org.combinators.ep.builder.scala - -//import org.combinators.ep.builder.scala.paradigm.ffi.Trees -//import org.combinators.ep.language.scala.{Config, CtorCtxt, MethodBodyCtxt} -//import org.combinators.ep.language.scala.Metho -//import org.combinators.ep.language.inbetween.CodeGenerator - -class CodeGenerator { -// val treesInMethod = { -// Trees[MethodBodyCtxt, paradigm.type, ObjectOriented]( -// paradigm, -// paradigm.methodBodyCapabilities.canAddImportInMethodBody -// )(ooParadigm) -// } -// -// val treesInConstructor = { -// Trees[CtorCtxt, paradigm.type, ObjectOriented]( -// paradigm, -// ooParadigm.constructorCapabilities.canAddImportInConstructor -// )(ooParadigm) -// } -} diff --git a/builder/src/main/scala/org/combinators/ep/builder/scala/Main.scala b/builder/src/main/scala/org/combinators/ep/builder/scala/Main.scala index 24a52ca0..17f0dd2a 100644 --- a/builder/src/main/scala/org/combinators/ep/builder/scala/Main.scala +++ b/builder/src/main/scala/org/combinators/ep/builder/scala/Main.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.builder.scala - -/*DD:LD:AD*/ +package org.combinators.ep.builder.scala /*DD:LD:AD*/ /** * To generate a single approach for a single stage in an Extension Graph, see [[DirectToDiskMain]] @@ -41,7 +39,7 @@ import cats.effect.{ExitCode, IO, IOApp} import org.apache.commons.io.FileUtils import org.combinators.cogen.FileWithPathPersistable.* import org.combinators.cogen.{Command, FileWithPath, FileWithPathPersistable} -import org.combinators.ep.approach.oo.{CoCoClean, ExtensibleVisitor, Interpreter, ObjectAlgebras, Traditional, TriviallyClean, Visitor, Visualize} +import org.combinators.ep.approach.oo.{CoCoClean, ExtensibleVisitor, Interpreter, ObjectAlgebras, RuntimeDispatch, Traditional, TriviallyClean, Visitor, Visualize} import org.combinators.ep.domain.Evolution import org.combinators.ep.domain.math.{A1, A1M3, A1M3I2, A3, C2, I2M3I1N1, M0, M1, M2, M2_ABS, M3, M3I1, M3W1, M4, M5, M6, M7, M7I2, M8, M9, N1, P1, Q1, V1, W1} import org.combinators.ep.domain.math.eips @@ -69,10 +67,14 @@ class Main(choice:String, select:String) { val ast: FullAST & TreesAST = new FinalBaseAST with FinalNameProviderAST with FinalArithmeticAST + with FinalArraysAST with FinalAssertionsAST with FinalBooleanAST + with FinalConsoleAST with FinalEqualsAST + with FinalExceptionsAST with FinalListsAST + with FinalMapsAST with FinalOperatorExpressionsAST with FinalRealArithmeticOpsAST with FinalStringAST @@ -101,7 +103,7 @@ class Main(choice:String, select:String) { val cocoCleanApproach: CoCoClean.WithParadigm[generator.paradigm.type] = CoCoClean[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.ooParadigm, generator.parametricPolymorphism)(generator.generics) val triviallyCleanApproach: TriviallyClean.WithParadigm[generator.paradigm.type] = TriviallyClean[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.ooParadigm) - //val dispatchApproach = RuntimeDispatch[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.imperative, generator.strings, generator.exceptions, generator.ooParadigm) + val dispatchApproach = RuntimeDispatch[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.imperative.imperativeInMethods, generator.strings.stringsInMethods, generator.exceptions.exceptionsInMethods, generator.ooParadigm) val algebraApproach: ObjectAlgebras.WithParadigm[generator.paradigm.type] = ObjectAlgebras[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.ooParadigm, generator.parametricPolymorphism)(generator.generics) val visualizeApproach: Visualize.WithParadigm[generator.paradigm.type] = Visualize[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.ooParadigm) @@ -117,7 +119,7 @@ class Main(choice:String, select:String) { case "interpreter" => interpreterApproach case "coco" => cocoCleanApproach case "trivially" => triviallyCleanApproach - case "dispatch" => ??? // not yet implemented b/c Exceptions not yet in inBetween + case "dispatch" => dispatchApproach case "algebra" => algebraApproach case _ => ??? @@ -716,7 +718,7 @@ object DirectToDiskMain extends IOApp { def run(args: List[String]): IO[ExitCode] = { // "M9", "J8", "A3", "O1OA", "OD3", "OO3", "V1", "D3", "I2M3I1N1", "O2" - val approach = if (args.isEmpty) "visitor" else args.head // {coco, O1OA} fails + val approach = if (args.isEmpty) "oo" else args.head // {coco, O1OA} fails if (approach == "exit") { sys.exit(0) } diff --git a/builder/src/main/scala/org/combinators/ep/builder/scala/paradigm/ffi/TreesAST.scala b/builder/src/main/scala/org/combinators/ep/builder/scala/paradigm/ffi/TreesAST.scala index a9a06329..ebb5ac43 100644 --- a/builder/src/main/scala/org/combinators/ep/builder/scala/paradigm/ffi/TreesAST.scala +++ b/builder/src/main/scala/org/combinators/ep/builder/scala/paradigm/ffi/TreesAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.builder.scala.paradigm.ffi +package org.combinators.ep.builder.scala.paradigm.ffi /*DI:LD:AI*/ import org.combinators.cogen.{FileWithPath, TypeRep} import org.combinators.ep.builder.inbetween.paradigm.ffi.TreesAST as InbetweenTreesAST @@ -17,8 +17,6 @@ trait TreesAST extends InbetweenTreesAST { self: ParametricPolymorphismAST & Bas type Node <: treesOpsOverride.Node } - - trait Tree extends treesOps.Tree with scalaBase.ooOverrides.ClassReferenceType { def qualifiedClassName: Seq[any.Name] = qualifiedClassNameTree } @@ -45,7 +43,6 @@ trait TreesAST extends InbetweenTreesAST { self: ParametricPolymorphismAST & Bas } } - val qualifiedClassNameTree: Seq[any.Name] = Seq("org", "combinators", "ep", "util", "Tree").map(n => scalaBaseFactory.name(n, n)) val qualifiedClassNameLeaf: Seq[any.Name] = Seq("org", "combinators", "ep", "util", "Leaf").map(n => scalaBaseFactory.name(n, n)) val qualifiedClassNameNode: Seq[any.Name] = Seq("org", "combinators", "ep", "util", "Node").map(n => scalaBaseFactory.name(n, n)) diff --git a/cogen/src/main/scala/org/combinators/cogen/AbstractSyntax.scala b/cogen/src/main/scala/org/combinators/cogen/AbstractSyntax.scala index 59a6eebe..9b3b7fc9 100644 --- a/cogen/src/main/scala/org/combinators/cogen/AbstractSyntax.scala +++ b/cogen/src/main/scala/org/combinators/cogen/AbstractSyntax.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ /** Provides type definitions for abstract syntax tree components. */ trait AbstractSyntax { diff --git a/cogen/src/main/scala/org/combinators/cogen/Command.scala b/cogen/src/main/scala/org/combinators/cogen/Command.scala index 9548d949..1debaae5 100644 --- a/cogen/src/main/scala/org/combinators/cogen/Command.scala +++ b/cogen/src/main/scala/org/combinators/cogen/Command.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ import cats._ import cats.data.State @@ -19,13 +19,17 @@ trait Command { def interpret[Context, Self >: this.type <: Command.WithResult[Result]](implicit interp: Understands[Context, Self]): Command.Generator[Context, Result] = { val self: Self = this - liftF[Command.Performable[Context, _], Result](Command.Performable[Context, Result, Self](self, interp)) + liftF[Command.Performable[Context, *], Result](new Command.Performable[Context, Result] { + type Cmd = Self + val cmd: Self = self + val interpreter: Understands[Context, Self] = interp + }) } } object Command { type WithResult[R] = Command { type Result = R } - type Generator[C, A] = Free[Performable[C, _], A] + type Generator[C, A] = Free[Performable[C, *], A] sealed trait Performable[Context, R] { type Cmd <: Command.WithResult[R] @@ -41,15 +45,15 @@ object Command { } def runGenerator[Context, Result](gen: Generator[Context, Result], inContext: Context): (Context, Result) = { - val compiler: Performable[Context, _] ~> State[Context, _] = new (Performable[Context, _] ~> State[Context, _]) { + val compiler: Performable[Context, *] ~> State[Context, *] = new (Performable[Context, *] ~> State[Context, *]) { def apply[A](fa: Performable[Context, A]): State[Context, A] = State[Context, A](ctxt => fa.interpreter.perform(ctxt, fa.cmd)) } gen.foldMap(compiler).run(inContext).value } - implicit def monadInstance[C]: Monad[Generator[C, _]] = - cats.free.Free.catsFreeMonadForFree[Performable[C, _]] + implicit def monadInstance[C]: Monad[Generator[C, *]] = + cats.free.Free.catsFreeMonadForFree[Performable[C, *]] def lift[Context, T](value: T): Command.Generator[Context, T] = monadInstance.pure(value) def skip[Context]: Generator[Context, Unit] = lift(()) diff --git a/cogen/src/main/scala/org/combinators/cogen/FileWithPath.scala b/cogen/src/main/scala/org/combinators/cogen/FileWithPath.scala index 7ba1609c..823af518 100644 --- a/cogen/src/main/scala/org/combinators/cogen/FileWithPath.scala +++ b/cogen/src/main/scala/org/combinators/cogen/FileWithPath.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ import org.combinators.templating.persistable.Persistable diff --git a/cogen/src/main/scala/org/combinators/cogen/FreshNameProvider.scala b/cogen/src/main/scala/org/combinators/cogen/FreshNameProvider.scala index 2ff96e3d..79b8d041 100644 --- a/cogen/src/main/scala/org/combinators/cogen/FreshNameProvider.scala +++ b/cogen/src/main/scala/org/combinators/cogen/FreshNameProvider.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ case class FreshNameProvider[Name]( pushName: (Name, Int) => Name, diff --git a/cogen/src/main/scala/org/combinators/cogen/InstanceRep.scala b/cogen/src/main/scala/org/combinators/cogen/InstanceRep.scala index 078f94c0..2ac1ab2c 100644 --- a/cogen/src/main/scala/org/combinators/cogen/InstanceRep.scala +++ b/cogen/src/main/scala/org/combinators/cogen/InstanceRep.scala @@ -1,6 +1,6 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ -/** A host language (Scala) instance, which can be represented inside of a domain. +/** A host language (Scala) instance, which can be represented inside a domain. * * In type theory this is encoded as a dependent sum, Sigma, where there exists a type and an instance for that type. * Check [[https://partialflow.wordpress.com/2017/07/26/dependent-types-type-level-programming/ this introduction]] diff --git a/cogen/src/main/scala/org/combinators/cogen/NameProvider.scala b/cogen/src/main/scala/org/combinators/cogen/NameProvider.scala index 63713892..f3b631d9 100644 --- a/cogen/src/main/scala/org/combinators/cogen/NameProvider.scala +++ b/cogen/src/main/scala/org/combinators/cogen/NameProvider.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ /** Provides mangled names for domain entities. */ abstract class NameProvider[Name] { diff --git a/cogen/src/main/scala/org/combinators/cogen/Tag.scala b/cogen/src/main/scala/org/combinators/cogen/Tag.scala index b4675bbc..177aec7a 100644 --- a/cogen/src/main/scala/org/combinators/cogen/Tag.scala +++ b/cogen/src/main/scala/org/combinators/cogen/Tag.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ /** Used to mark special operations (needed for isOp logic) and possible useful in other ways. */ trait Tag {} diff --git a/cogen/src/main/scala/org/combinators/cogen/TestCase.scala b/cogen/src/main/scala/org/combinators/cogen/TestCase.scala index bcc8f0ab..18356bd5 100644 --- a/cogen/src/main/scala/org/combinators/cogen/TestCase.scala +++ b/cogen/src/main/scala/org/combinators/cogen/TestCase.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ /** Marks any inheriting object as a model of a software test case. */ trait TestCase { diff --git a/cogen/src/main/scala/org/combinators/cogen/TypeRep.scala b/cogen/src/main/scala/org/combinators/cogen/TypeRep.scala index 5e172ee7..07acffaf 100644 --- a/cogen/src/main/scala/org/combinators/cogen/TypeRep.scala +++ b/cogen/src/main/scala/org/combinators/cogen/TypeRep.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ /** * Represents a host language (Scala) type within the domain. @@ -39,6 +39,11 @@ object TypeRep { type HostType = scala.Boolean } + /** Represents the Scala type `Char`. */ + case object Char extends TypeRep { + type HostType = scala.Char + } + /** Represents the type `Seq[A]` */ case class Sequence[T](elemTpe: TypeRep.OfHostType[T]) extends TypeRep { type HostType = Seq[T] @@ -46,7 +51,12 @@ object TypeRep { /** Represents the type `Array[T]` */ case class Array[T](elemTpe: TypeRep.OfHostType[T]) extends TypeRep { - type HostType = Array[T] + type HostType = scala.Array[T] + } + + /** Represents the type `Map[K,V]` */ + case class Map[K,V](keyTpe: TypeRep.OfHostType[K], elemTpe: TypeRep.OfHostType[V]) extends TypeRep { + type HostType = scala.collection.immutable.Map[K,V] } /** Represents the type A => B */ diff --git a/cogen/src/main/scala/org/combinators/cogen/Understands.scala b/cogen/src/main/scala/org/combinators/cogen/Understands.scala index a219b62d..68d27b65 100644 --- a/cogen/src/main/scala/org/combinators/cogen/Understands.scala +++ b/cogen/src/main/scala/org/combinators/cogen/Understands.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen +package org.combinators.cogen /*DI:LI:AI*/ @scala.annotation.implicitNotFound(msg = "Context ${Context} does not understand ${Cmd}") trait Understands[Context, Cmd <: Command] { diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/AnyParadigm.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/AnyParadigm.scala index 4603d588..df2103b3 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/AnyParadigm.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/AnyParadigm.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm +package org.combinators.cogen.paradigm /*DI:LI:AI*/ import org.combinators.cogen.{AbstractSyntax, Command, FileWithPath, Understands, TypeRep} import Command._ @@ -179,10 +179,6 @@ trait AnyParadigm { implicit val canDebugInMethodBody: Understands[MethodBodyContext, Debug] def debug(tag:String = ""): Generator[MethodBodyContext, Unit] = AnyParadigm.capability(Debug(tag)) - - implicit val canOutputToConsole: Understands[MethodBodyContext, OutputToConsole[Expression]] - def output(expr:Expression): Generator[MethodBodyContext, Unit] = - AnyParadigm.capability(OutputToConsole[Expression](expr)) implicit val canAddImportInMethodBody: Understands[MethodBodyContext, AddImport[Import]] def addImport(imp: Import): Generator[MethodBodyContext, Unit] = @@ -245,8 +241,8 @@ object AnyParadigm { def capability[Ctxt, R, Cmd <: Command.WithResult[R]] (cmd: Cmd) - (implicit interp: Understands[Ctxt, Cmd]): Generator[Ctxt, R] = { - cmd.interpret[Ctxt, Cmd](interp) + (using interp: Understands[Ctxt, Cmd]): Generator[Ctxt, R] = { + cmd.interpret[Ctxt, Cmd](using interp) } object syntax { diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/Functional.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/Functional.scala index 282db79d..db93e7d1 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/Functional.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/Functional.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm +package org.combinators.cogen.paradigm /*DI:LI:AI*/ import org.combinators.cogen.{TypeRep, Command, Understands} import Command.Generator diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/Generics.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/Generics.scala index 17aa46b4..a75d6ca3 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/Generics.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/Generics.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm +package org.combinators.cogen.paradigm /*DI:LI:AI*/ import org.combinators.cogen.{Command, Understands} import Command.Generator diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ObjectOriented.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ObjectOriented.scala index fad25c8a..99e09502 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ObjectOriented.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ObjectOriented.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm +package org.combinators.cogen.paradigm /*DI:LI:AI*/ import org.combinators.cogen.{Command, Understands, TypeRep} import Command.Generator @@ -83,7 +83,7 @@ case class SelfReference[Expression]() extends Command { type Result = Expression } -/** Used for super. or (when tpe exists) then qn.super. */ +/** Used for 'super' or (when tpe exists) then 'qn.super'. */ case class SuperReference[Name, Expression](qualifiedName:Seq[Name] = Seq.empty) extends Command { type Result = Expression } @@ -136,11 +136,6 @@ trait ObjectOriented { def addImplemented(interface: Type): Generator[ClassContext, Unit] = AnyParadigm.capability(AddImplemented(interface)) - // FIRST REMOVE CAPABILITY - implicit val canRemoveMethodFromClass: Understands[ClassContext, RemoveMethod[Type, Name]] - def removeMethod(interface: Type, name:Name): Generator[ClassContext, Unit] = - AnyParadigm.capability(RemoveMethod(interface, name)) - implicit val canAddFieldInClass: Understands[ClassContext, AddField[Name, Type, Expression]] def addField(name: Name, tpe: Type, init:Option[Expression] = Option.empty): Generator[ClassContext, Unit] = AnyParadigm.capability(AddField[Name, Type, Expression](name, tpe, initializer = init)) diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphism.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphism.scala index 127d8ac9..9eddc7b4 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphism.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphism.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm +package org.combinators.cogen.paradigm /*DI:LI:AI*/ import org.combinators.cogen.{Command, Understands} import Command.Generator @@ -28,7 +28,7 @@ trait ParametricPolymorphism { AnyParadigm.capability(AddTypeParameter[Name, TypeParameterContext](name, spec)) implicit val canGetTypeArgumentsInMethod: Understands[MethodBodyContext, GetTypeArguments[Type]] - def getTypeArguments(): Generator[MethodBodyContext, Seq[Type]] = + def getTypeArguments: Generator[MethodBodyContext, Seq[Type]] = AnyParadigm.capability(GetTypeArguments[Type]()) implicit val canApplyTypeInMethod: Understands[MethodBodyContext, Apply[Type, Type, Type]] diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphismInADTContexts.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphismInADTContexts.scala index 757e0618..6c645e0f 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphismInADTContexts.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ParametricPolymorphismInADTContexts.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm +package org.combinators.cogen.paradigm /*DI:LI:AI*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.Understands diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/control/Functional.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/control/Functional.scala index d8fd16ec..5c4d478c 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/control/Functional.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/control/Functional.scala @@ -1,7 +1,7 @@ package org.combinators.cogen.paradigm.control import org.combinators.cogen.paradigm.{AnyParadigm, Apply, IfThenElse, Reify} -import org.combinators.cogen.{TypeRep, Command, Understands} +import org.combinators.cogen.{Command, TypeRep, Understands} import Command.Generator case class PatternMatch[MethodBodyContext, PatternContext, Expression]( diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arithmetic.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arithmetic.scala index 535ab46a..05dabeb1 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arithmetic.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arithmetic.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arrays.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arrays.scala index 5be15cf3..a37ab7b9 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arrays.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Arrays.scala @@ -1,10 +1,14 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ -import org.combinators.cogen.paradigm.{AnyParadigm, Apply} -import org.combinators.cogen.{Command, Understands} +import org.combinators.cogen.paradigm.{AnyParadigm, Apply, Reify} +import org.combinators.cogen.{Command, TypeRep, Understands} import Command.Generator -case class CreateArray[Type](elementType: Type) +// if this has contents, must pass in Seq[Int] to be able to group one-dimensional sequence into appropriate sub-structures. +case class CreateArray[Type,Expression](elementType: Type, dimensions: Seq[Expression], contentSpec:Option[(Seq[Int], Seq[Expression])]) extends Command { + override type Result = Expression +} + case class Get() case class Set() case class Length() @@ -14,21 +18,32 @@ trait Arrays[Context] extends FFI { import syntax._ trait ArrayCapabilities { - implicit val canCreate: Understands[Context, Apply[CreateArray[Type], Expression, Expression]] - def create(elemTpe: Type, contents: Seq[Expression]): Generator[Context, Expression] = - AnyParadigm.capability(Apply[CreateArray[Type], Expression, Expression](CreateArray(elemTpe), contents)) + implicit val canCreate: Understands[Context, CreateArray[Type,Expression]] + def create(elemTpe: Type, dimensions: Seq[Expression], contentSpec: Option[(Seq[Int], Seq[Expression])]): Generator[Context, Expression] = + AnyParadigm.capability(CreateArray[Type,Expression](elemTpe, dimensions, contentSpec)) + + def create(elemTpe: Type, dimensions: Seq[Int], contentSpec: Seq[Expression]) + (implicit reify: Understands[Context, Reify[Int, Expression]]) + : Generator[Context, Expression] = { + import AnyParadigm.syntax.forEach + for { + dimExps <- forEach(dimensions) { dim => AnyParadigm.capability(Reify[Int, Expression](TypeRep.Int, dim)) } + result <- create(elemTpe, dimExps, Some((dimensions, contentSpec))) + } yield result + } implicit val canGet: Understands[Context, Apply[Get, Expression, Expression]] - def get(array: Expression, pos:Expression): Generator[Context, Expression] = - AnyParadigm.capability(Apply[Get, Expression, Expression](Get(), Seq(array, pos))) + def get(array: Expression, indices:Seq[Expression]): Generator[Context, Expression] = + AnyParadigm.capability(Apply[Get, Expression, Expression](Get(), array +: indices)) + // construct Sequence as (array, newValue, indices) since there is always a single newValue but may be multiple indices implicit val canSet: Understands[Context, Apply[Set, Expression, Expression]] - def set(array: Expression, pos:Expression, value:Expression): Generator[Context, Expression] = - AnyParadigm.capability(Apply[Set, Expression, Expression](Set(), Seq(array, pos, value))) + def set(array: Expression, indices:Seq[Expression], value:Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[Set, Expression, Expression](Set(), Seq(array, value) ++ indices)) implicit val canLength: Understands[Context, Apply[Length, Expression, Expression]] - def length(array:Expression): Generator[Context, Expression] = - AnyParadigm.capability(Apply[Length, Expression, Expression](Length(), Seq(array))) + def length(array:Expression, dimensions:Seq[Expression]): Generator[Context, Expression] = + AnyParadigm.capability(Apply[Length, Expression, Expression](Length(), array +: dimensions)) } val arrayCapabilities: ArrayCapabilities } diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Assertions.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Assertions.scala index 56893694..0a889549 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Assertions.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Assertions.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Booleans.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Booleans.scala index 403e2453..bf913234 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Booleans.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Booleans.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Console.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Console.scala index 793d5ad3..8e5488a0 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Console.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Console.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Equality.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Equality.scala index 894c7ab8..d9992c78 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Equality.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Equality.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Exceptions.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Exceptions.scala index e50cec08..5c374760 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Exceptions.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Exceptions.scala @@ -1,6 +1,6 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ -import org.combinators.cogen.paradigm.{AnyParadigm} +import org.combinators.cogen.paradigm.AnyParadigm import org.combinators.cogen.{Command, Understands} import Command.Generator @@ -11,14 +11,14 @@ case class Exception[Expression,Stmt](exp:Expression) extends Command { trait Exceptions[Context] extends FFI { import base.syntax._ - trait ExceptionCapabilities { + trait ExceptionsCapabilities { implicit val canRaise: Understands[Context, Exception[Expression, Statement]] def raise(exp: Expression): Generator[Context, Statement] = AnyParadigm.capability(Exception[Expression, Statement](exp)) } - val exceptionCapabilities: ExceptionCapabilities + val exceptionsCapabilities: ExceptionsCapabilities } object Exceptions { diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/FFI.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/FFI.scala index 1e24b986..6d65cd0d 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/FFI.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/FFI.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.AnyParadigm import org.combinators.cogen.Command.Generator diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Lists.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Lists.scala index bea87fd8..5d65addd 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Lists.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Lists.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Maps.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Maps.scala new file mode 100644 index 00000000..cb97e32b --- /dev/null +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Maps.scala @@ -0,0 +1,39 @@ +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ + +import org.combinators.cogen.paradigm.{AnyParadigm, Apply} +import org.combinators.cogen.{Command, Understands} +import Command.Generator + +case class CreateMap[Type](keyType:Type, elementType: Type) +case class GetOrElse() +case class ContainsKey() +case class Put[Type](keyType: Type, valueType: Type) + +trait Maps[Context] extends FFI { + import base._ + import syntax._ + + trait MapCapabilities { + implicit val canCreate: Understands[Context, Apply[CreateMap[Type], (Expression,Expression), Expression]] + def create(keyTpe: Type, elemTpe: Type, values:(Expression,Expression)*): Generator[Context, Expression] = + AnyParadigm.capability(Apply(CreateMap(keyTpe, elemTpe), values)) + + implicit val canContainsKey: Understands[Context, Apply[ContainsKey, Expression, Expression]] + def contains(map: Expression, key: Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[ContainsKey, Expression, Expression](ContainsKey(), Seq(map, key))) + + implicit val canGet: Understands[Context, Apply[GetOrElse, Expression, Expression]] + def getOrElse(map: Expression, key: Expression, defaultVal: Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[GetOrElse, Expression, Expression](GetOrElse(), Seq(map, key, defaultVal))) + + implicit val canPut: Understands[Context, Apply[Put[Type], Expression, Expression]] + def put(map: Expression, keyType: Type, valueType: Type, key:Expression, value:Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[Put[Type], Expression, Expression](Put(keyType, valueType), Seq(map, key, value))) + + } + val mapCapabilities: MapCapabilities +} + +object Maps { + type WithBase[Ctxt, B <: AnyParadigm] = Maps[Ctxt] { val base: B } +} diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/RealArithmetic.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/RealArithmetic.scala index adcc9d7f..805ed37c 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/RealArithmetic.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/RealArithmetic.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} @@ -10,6 +10,9 @@ case class Log[T]() case class Sin[T]() case class Cos[T]() +case class Max[T]() +case class Min[T]() + case class Abs[T]() case class Floor[T]() @@ -36,6 +39,14 @@ trait RealArithmetic[Context, T] extends FFI { def log(base: Expression, x: Expression): Generator[Context, Expression] = AnyParadigm.capability(Apply[Log[T], Expression, Expression](Log[T](), Seq(base, x))) + implicit val canMax: Understands[Context, Apply[Max[T], Expression, Expression]] + def max(left: Expression, right: Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[Max[T], Expression, Expression](Max[T](), Seq(left, right))) + + implicit val canMin: Understands[Context, Apply[Min[T], Expression, Expression]] + def min(left: Expression, right: Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[Min[T], Expression, Expression](Min[T](), Seq(left, right))) + implicit val canSin: Understands[Context, Apply[Sin[T], Expression, Expression]] def sin(x: Expression): Generator[Context, Expression] = AnyParadigm.capability(Apply[Sin[T], Expression, Expression](Sin[T](), Seq(x))) diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Strings.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Strings.scala index 4ddfbec3..ac2086e9 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Strings.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Strings.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply, Reify} import org.combinators.cogen.{Command, Understands, TypeRep} @@ -8,6 +8,8 @@ import scala.annotation.tailrec case class StringAppend() case class GetStringLength() +case class GetCharAt() +case class SubString() case class ToString[Type](sourceType: Type) trait Strings[Context] extends FFI { @@ -18,6 +20,14 @@ trait Strings[Context] extends FFI { def getStringLength(expression: Expression): Generator[Context, Expression] = AnyParadigm.capability(Apply[GetStringLength, Expression, Expression](GetStringLength(), Seq(expression))) + implicit val canSubString: Understands[Context, Apply[SubString, Expression, Expression]] + def subString(expression: Expression, start:Expression, exclusiveEnd:Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[SubString, Expression, Expression](SubString(), Seq(expression, start, exclusiveEnd))) + + implicit val canGetCharAt: Understands[Context, Apply[GetCharAt, Expression, Expression]] + def getCharAt(expression: Expression, pos:Expression): Generator[Context, Expression] = + AnyParadigm.capability(Apply[GetCharAt, Expression, Expression](GetCharAt(), Seq(expression, pos))) + implicit val canAppend: Understands[Context, Apply[StringAppend, Expression, Expression]] def stringAppend(xs: Expression*): Generator[Context, Expression] = AnyParadigm.capability(Apply[StringAppend, Expression, Expression](StringAppend(), xs)) diff --git a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Time.scala b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Time.scala index 19d529d4..c77428f6 100644 --- a/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Time.scala +++ b/cogen/src/main/scala/org/combinators/cogen/paradigm/ffi/Time.scala @@ -1,4 +1,4 @@ -package org.combinators.cogen.paradigm.ffi +package org.combinators.cogen.paradigm.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AnyParadigm, Apply} import org.combinators.cogen.{Command, Understands} diff --git a/core/src/main/scala/org/combinators/ep/domain/GraphViz.scala b/core/src/main/scala/org/combinators/ep/domain/GraphViz.scala index 6a18301c..5197a562 100644 --- a/core/src/main/scala/org/combinators/ep/domain/GraphViz.scala +++ b/core/src/main/scala/org/combinators/ep/domain/GraphViz.scala @@ -155,7 +155,7 @@ object GraphViz { }) }) - // even if neither types or ops (especially then, since a merge) must find dependencies. + // even if neither types nor ops (especially then, since a merge) must find dependencies. }) addedNodes.foreach(pair => fileWriter.write (pair._1 + "\n")) diff --git a/core/src/main/scala/org/combinators/ep/domain/Model.scala b/core/src/main/scala/org/combinators/ep/domain/Model.scala index 03c43616..5f1a8c8a 100644 --- a/core/src/main/scala/org/combinators/ep/domain/Model.scala +++ b/core/src/main/scala/org/combinators/ep/domain/Model.scala @@ -270,7 +270,7 @@ class GenericModel(val name:String, /** * Determines if this model or its history contain any binary methods. * - * Typical usage is to call getModel.flatten before calling this method. + * Typical usage is to call 'getModel.flatten' before calling this method. */ def hasBinaryMethod: Boolean = toSeq.exists(_.ops.exists(_.isBinary(this))) @@ -278,7 +278,7 @@ class GenericModel(val name:String, /** * Determine if this model or its history contain any producer operations. * - * Typical usage is to call getModel.flatten before calling this method. + * Typical usage is to call 'getModel.flatten' before calling this method. */ def hasProducerOperation: Boolean = toSeq.exists(_.ops.exists(_.isProducer(this))) @@ -366,8 +366,8 @@ class GenericModel(val name:String, * * Use `evolve` to obtain the next model and [[org.combinators.ep.domain.GenericModel.base]] for the initial one. * - * This will be renamed LinearModel and a superclass is non-linear model. In nonlinear model, could - * have a linearize() method that "zips" up to create a linear model. + * This will be renamed LinearModel and a superclass is non-linear model. In non-linear model, there could be + * a linearize() method that "zips" up to create a linear model. * * @note Names act as unique identifiers within the context of one domain. */ diff --git a/core/src/main/scala/org/combinators/ep/domain/abstractions/abstractions.scala b/core/src/main/scala/org/combinators/ep/domain/abstractions/abstractions.scala index 5dea2e27..837a3b5c 100644 --- a/core/src/main/scala/org/combinators/ep/domain/abstractions/abstractions.scala +++ b/core/src/main/scala/org/combinators/ep/domain/abstractions/abstractions.scala @@ -39,7 +39,7 @@ object DataTypeCase { def unary(name: String)(implicit domain: GenericModel): DataTypeCase = DataTypeCase(name, Seq(Attribute.inner)) - /** Constructs a type case with a two attributes "left" and "right" of the base data type + /** Constructs a type case with two attributes "left" and "right" of the base data type * of the implicitly given domain model. */ def binary(name: String)(implicit domain: GenericModel): DataTypeCase = @@ -138,7 +138,7 @@ object Operation { /** Returns a [[org.combinators.ep.domain.matchers.Matchable]] transforming the given function on * [[org.combinators.ep.domain.abstractions.Parameter Parameters]] and a - * [[TypeRep return type representation]] to a a partial function on a + * [[TypeRep return type representation]] to a partial function on a * signature of operations of the same name as the given operation. * * Example: diff --git a/core/src/main/scala/org/combinators/ep/domain/extensions/extensions.scala b/core/src/main/scala/org/combinators/ep/domain/extensions/extensions.scala index 50f26a28..67131e9b 100644 --- a/core/src/main/scala/org/combinators/ep/domain/extensions/extensions.scala +++ b/core/src/main/scala/org/combinators/ep/domain/extensions/extensions.scala @@ -1,9 +1,8 @@ package org.combinators.ep.domain.extensions /*DI:LI:AI*/ -import org.combinators.cogen.{InstanceRep, NameProvider, TypeRep} +import org.combinators.cogen.{NameProvider, TypeRep} import org.combinators.ep.domain.GenericModel import org.combinators.ep.domain.abstractions._ -import org.combinators.ep.domain.instances.DataTypeInstance /** * EpCoGen extension of NameProvider from CoGen provides the ability to generate (capital) Names for many different concepts diff --git a/core/src/main/scala/org/combinators/ep/generator/EvolutionImplementationProvider.scala b/core/src/main/scala/org/combinators/ep/generator/EvolutionImplementationProvider.scala index 5a04f5bb..392a0f17 100644 --- a/core/src/main/scala/org/combinators/ep/generator/EvolutionImplementationProvider.scala +++ b/core/src/main/scala/org/combinators/ep/generator/EvolutionImplementationProvider.scala @@ -2,9 +2,8 @@ package org.combinators.ep.generator /*DI:LI:AI*/ import cats.kernel.Monoid import org.combinators.cogen.paradigm.AnyParadigm -import org.combinators.cogen.paradigm.ffi.FFI import org.combinators.ep.domain.GenericModel -import org.combinators.ep.domain.abstractions.{DataTypeCase, Operation} +import org.combinators.ep.domain.abstractions.Operation import org.combinators.cogen.Command import Command.Generator import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, SendRequest} @@ -21,36 +20,8 @@ trait EvolutionImplementationProvider[-AIP <: ApproachImplementationProvider] { */ def initialize(forApproach: AIP): Generator[forApproach.paradigm.ProjectContext, Unit] -// /** Accesses API with PotentialRequest derived from onRequest. */ -// def applicableIn(forApproach: AIP)(onRequest: ReceivedRequest[forApproach.paradigm.syntax.Expression], currentModel:GenericModel): Option[GenericModel] = -// applicableIn(forApproach, PotentialRequest(onRequest.onType, onRequest.tpeCase, onRequest.request.op), currentModel) -// -// /** For more complicated ExtensionGraphs, this returns most appropriate evolution for which an EIP is available. -// * In linear histories, this is the most recent. For histories involving merging, the EIP is responsible -// * for choosing which branch(es) to forward request to. Takes care to check against "current model" to -// * avoid returning an implementation for the future. */ -// def applicableIn(forApproach: AIP, potentialRequest: PotentialRequest, currentModel:GenericModel): Option[GenericModel] = -// if ((model == currentModel || model.before(currentModel)) && applicable(forApproach, potentialRequest)) { -// Some(model) -// } else { -// None -// } -// -// /** Tests if this evolution implementation provider is applicable for the given request */ -// def applicable(forApproach: AIP)(onRequest: ReceivedRequest[forApproach.paradigm.syntax.Expression]): Boolean = -// applicable(forApproach, PotentialRequest(onRequest.onType, onRequest.tpeCase, onRequest.request.op)) -// -// /** Tests if this evolution implementation provider is applicable for the given request */ -// def applicable(forApproach: AIP, onRequest: PotentialRequest): Boolean -// -// /** Can vary by operation and data type. */ -// @Deprecated def dependencies(op:Operation, dt:DataTypeCase) : Option[Set[Operation]] = None - def dependencies(potentialRequest: PotentialRequest): Option[Set[Operation]] = None -// @Deprecated def evolutionSpecificDependencies(op: Operation, dt: DataTypeCase): Map[GenericModel, Set[Operation]] = -// dependencies(op, dt).map(deps => Map(model -> deps)).getOrElse(Map.empty) - def evolutionSpecificDependencies(potentialRequest: PotentialRequest): Map[GenericModel, Set[Operation]] = dependencies(potentialRequest).map(deps => Map(model -> deps)).getOrElse(Map.empty) @@ -187,11 +158,6 @@ object EvolutionImplementationProvider { case _ => second.logic(forApproach)(onRequest) } -// if (first.applicable(forApproach)(onRequest)) { -// first.logic(forApproach)(onRequest) -// } else { -// second.logic(forApproach)(onRequest) -// } } } } diff --git a/core/src/test/scala/org/combinators/ep/TestDriver.scala b/core/src/test/scala/org/combinators/ep/TestDriver.scala deleted file mode 100644 index 8ad295cc..00000000 --- a/core/src/test/scala/org/combinators/ep/TestDriver.scala +++ /dev/null @@ -1,8 +0,0 @@ -package org.combinators.ep - -class TestDriver( - - -) { - -} diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/M0.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/M0.scala index 7c0e5cc8..79a94bed 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/M0.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/M0.scala @@ -31,7 +31,7 @@ object M0 extends Evolution { val addi: DataTypeInstance = AddInst(LitInst(1.0), LitInst(2.0)) val liti: DataTypeInstance = LitInst(5.0) - // defining tests exactly once means they can be eliminated later (in Evolution) when it uses 'distinct' on past test cases) + // defining tests exactly once means they can be eliminated later (in Evolution) when it uses 'distinct' on past test cases val m0_test_1: TestCase = EqualsTestCase(getModel.baseDataType, addi, Eval, DoubleInst(3.0)) val m0_test_2: TestCase = EqualsTestCase(getModel.baseDataType, liti, Eval, DoubleInst(5.0)) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1.scala index 2808c2d5..ae50cfc9 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1.scala @@ -70,6 +70,7 @@ object A1 { case _ => ??? } + //noinspection SpellCheckingInspection val result = for { atts <- forEach (onRequest.tpeCase.attributes) { att => diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1M3.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1M3.scala index e03121ea..5ac81adc 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1M3.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/A1M3.scala @@ -1,3 +1,4 @@ +//noinspection SpellCheckingInspection package org.combinators.ep.domain.math.eips /*DD:LI:AI*/ import org.combinators.cogen.paradigm.AnyParadigm diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/C2.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/C2.scala index 332c33bc..4f3fd8df 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/C2.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/C2.scala @@ -11,7 +11,7 @@ import org.combinators.ep.generator.EvolutionImplementationProvider.monoidInstan import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, Request, SendRequest} import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionImplementationProvider} -// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in an uniform way. +// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in a uniform way. sealed class C2[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementationProvider.WithParadigm[P], IfBlockType](val paradigm: P) { type IfThenElseCommand = (paradigm.syntax.Expression, diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M2_ABS.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M2_ABS.scala index cf727b46..dc21952d 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M2_ABS.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M2_ABS.scala @@ -11,7 +11,7 @@ import org.combinators.ep.generator.EvolutionImplementationProvider.monoidInstan import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, Request, SendRequest} import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionImplementationProvider} -// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in an uniform way. +// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in a uniform way. sealed class M2_ABS[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementationProvider.WithParadigm[P], IfBlockType](val paradigm: P) { type IfThenElseCommand = (paradigm.syntax.Expression, diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M3W1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M3W1.scala index d0a0058c..5bcefb71 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M3W1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M3W1.scala @@ -11,7 +11,7 @@ import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedReq import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionImplementationProvider} /** Upon merging M3 and W1 there is a need for MultByx(Divd, Mult, Neg) as well as a need for - * (Collect,Simplify,Id,AsTree,Equals,PowBy)xPower + * (Collect, Simplify, ID, AsTree, Equals, PowBy) x Power * * These all have to be captured here... */ diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M4.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M4.scala index 37e7d0bb..8e62cd4d 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M4.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M4.scala @@ -12,7 +12,7 @@ import org.combinators.ep.generator.EvolutionImplementationProvider.monoidInstan import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, Request, SendRequest} // Code for M4. Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be -// used in an uniform way. +// used in a uniform way. sealed class M4[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementationProvider.WithParadigm[P], IfBlockType](val paradigm: P) { type IfThenElseCommand = (paradigm.syntax.Expression, diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7.scala index b0422ab3..df0c6a9f 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7.scala @@ -103,7 +103,7 @@ object M7 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Know you have add data type so you can construct it + // Know you have `Add` data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M3.Mult, resultVar, onRequest.selfReference) @@ -171,7 +171,7 @@ object M7 { leftSide <- forApproach.dispatch(SendRequest( innerLit, math.M2.getModel.baseDataType, - Request(math.M7.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp some how? + Request(math.M7.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp somehow? )) res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M3.Mult, leftSide, left) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7I2.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7I2.scala index b65b3a65..c3258baf 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7I2.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7I2.scala @@ -13,7 +13,7 @@ import org.combinators.ep.generator.EvolutionImplementationProvider.monoidInstan import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, Request, SendRequest} /** Upon merging M7 and I2 there is a need for MultByx(Divd, Mult, Neg) as well as a need for - * (Collect,Simplify,Id,AsTree,Equals,PowBy)xPower + * (Collect,Simplify,ID,AsTree,Equals,PowBy)xPower * * These all have to be captured here... */ @@ -190,7 +190,7 @@ sealed class M7I2[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementat } yield Some(res) case p@math.M7.PowBy => // on Power - // must handle Power dataType. HERE WE CAN OPTIMIZED. + // must handle Power dataType. HERE WE CAN OPTIMIZE. for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.systemI.I2.Power, onRequest.selfReference, onRequest.request.arguments.head._2) } yield Some(res) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7funct.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7funct.scala index 3578b920..1565d6d9 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7funct.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M7funct.scala @@ -201,7 +201,7 @@ object M7funct { leftSide <- forApproach.dispatch(SendRequest( innerLit, math.M2.getModel.baseDataType, - Request(math.M7.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp some how? + Request(math.M7.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp somehow? )) res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M3.Mult, leftSide, left) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M8.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M8.scala index 6cc1f37a..205a0f17 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M8.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/M8.scala @@ -12,7 +12,7 @@ import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionIm import org.combinators.ep.generator.EvolutionImplementationProvider.monoidInstance import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, Request, SendRequest} -// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in an uniform way. +// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in a uniform way. sealed class M8[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementationProvider.WithParadigm[P], IfBlockType](val paradigm: P) { type IfThenElseCommand = diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1.scala index ea6ad126..e8db9c73 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1.scala @@ -106,7 +106,7 @@ object N1 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Now you have add data type so you can construct it + // Now you have `Add` data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M3.Mult, resultVar, onRequest.selfReference) @@ -175,7 +175,7 @@ object N1 { leftSide <- forApproach.dispatch(SendRequest( innerLit, math.M2.getModel.baseDataType, - Request(math.N1.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp some how? + Request(math.N1.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp somehow? )) res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M3.Mult, leftSide, left) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1funct.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1funct.scala index 6ffc72bb..ef219627 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1funct.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/N1funct.scala @@ -201,7 +201,7 @@ object N1funct { leftSide <- forApproach.dispatch(SendRequest( innerLit, math.M2.getModel.baseDataType, - Request(math.M7.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp some how? + Request(math.M7.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp somehow? )) res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M3.Mult, leftSide, left) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemD/D1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemD/D1.scala index 0736192d..25b11977 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemD/D1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemD/D1.scala @@ -92,7 +92,7 @@ object D1 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Know you have add data type so you can construct it + // Know you have the 'Add' data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M0.Add, resultVar, onRequest.request.arguments.head._2) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemI/I1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemI/I1.scala index b2b206c3..f82fecfd 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemI/I1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemI/I1.scala @@ -94,7 +94,7 @@ object I1 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Know you have add data type so you can construct it + // Know you have `ADD` data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M0.Add, resultVar, onRequest.request.arguments.head._2) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J1.scala index 7ae49daa..b7b2d2c0 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J1.scala @@ -94,7 +94,7 @@ object J1 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Know you have add data type so you can construct it + // Know you have `Add` data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M0.Add, resultVar, onRequest.request.arguments.head._2) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J3.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J3.scala index 18cb44af..d18a6825 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J3.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J3.scala @@ -167,7 +167,7 @@ object J3 { } else if (onRequest.request.op == math.systemJ.J2.isOp(onRequest.tpeCase)) { genericLogic(forApproach)(onRequest) // same isOpTypeCase applied to TypeCase can pass in } else { - // if opname is a "isSub" or "isAdd" for older typecase, but we are in newest one? Still send to generic logic + // if opname is a "isSub" or "isAdd" for older typecase, but we are in the newest one? Still send to generic logic val pastOps = math.systemJ.J2.isOps(model.flatten.typeCases) if (pastOps.contains(onRequest.request.op)) { genericLogic(forApproach)(onRequest) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6.scala index 99de32a6..27572449 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6.scala @@ -118,7 +118,7 @@ object J6 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Know you have add data type so you can construct it + // Know you have `Add` data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.systemJ.J2.Mult, resultVar, onRequest.selfReference) @@ -190,7 +190,7 @@ object J6 { leftSide <- forApproach.dispatch(SendRequest( innerLit, systemJ.J6.getModel.baseDataType, - Request(systemJ.J6.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp some how? + Request(systemJ.J6.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp somehow? )) res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.systemJ.J2.Mult, leftSide, left) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6funct.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6funct.scala index b40ed903..c572db0d 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6funct.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJ/J6funct.scala @@ -217,7 +217,7 @@ object J6funct { leftSide <- forApproach.dispatch(SendRequest( innerLit, systemJ.J6.getModel.baseDataType, - Request(systemJ.J6.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp some how? + Request(systemJ.J6.PowBy, Map(Parameter("other", onRequest.request.op.returnType) -> onRequest.attributes.head._2)) // MUST contain exp somehow? )) res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.systemJ.J2.Mult, leftSide, left) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/J7.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/J7.scala index 25094661..e8f496fc 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/J7.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/J7.scala @@ -15,7 +15,7 @@ import org.combinators.ep.generator.EvolutionImplementationProvider.monoidInstan import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedRequest, Request, SendRequest} import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionImplementationProvider} -// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in an uniform way. +// Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be used in a uniform way. sealed class J7[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementationProvider.WithParadigm[P], IfBlockType](val paradigm: P) { type IfThenElseCommand = @@ -186,7 +186,7 @@ sealed class J7[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementatio } else if (onRequest.request.op == math.systemJ.J2.isOp(onRequest.tpeCase)) { genericLogic(forApproach)(onRequest) // same isOpTypeCase applied to TypeCase can pass in } else { - // if opname is a "isSub" or "isAdd" for older typecase, but we are in newest one? Still send to generic logic + // if opname is a "isSub" or "isAdd" for older typecase, but we are in the newest one? Still send to generic logic val pastOps = math.systemJ.J2.isOps(model.flatten.typeCases) if (pastOps.contains(onRequest.request.op)) { genericLogic(forApproach)(onRequest) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/K2J6.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/K2J6.scala index bc64dee1..fcc2f112 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/K2J6.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemJK/K2J6.scala @@ -14,7 +14,7 @@ import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedReq import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionImplementationProvider} /** Upon merging M7 and I2 there is a need for MultByx(Divd, Mult, Neg) as well as a need for - * (Collect,Simplify,Id,AsTree,Equals,PowBy)xPower + * (Collect, Simplify, ID, AsTree, Equals, PowBy) x Power * * These all have to be captured here... */ @@ -296,7 +296,7 @@ sealed class K2J6[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementat case math.systemK.K2.Collect => k2Provider.genericLogic(forApproach)(onRequest) case p@math.systemJ.J6.PowBy => // on Power - // must handle Power dataType. HERE WE CAN OPTIMIZED. + // must handle Power dataType. HERE WE CAN OPTIMIZE. for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.systemK.K1.Power, onRequest.selfReference, onRequest.request.arguments.head._2) } yield Some(res) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K1.scala index fdf2e057..fb410f5e 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K1.scala @@ -76,7 +76,7 @@ object K1 { } else if (onRequest.request.op == math.systemJ.J2.isOp(onRequest.tpeCase)) { genericLogic(forApproach)(onRequest) // same isOpTypeCase applied to TypeCase can pass in } else { - // if opname is a "isSub" or "isAdd" for older typecase, but we are in newest one? Still send to generic logic + // if opname is a "isSub" or "isAdd" for older typecase, but we are in the newest one? Still send to generic logic val pastOps = math.systemJ.J2.isOps(model.flatten.typeCases) if (pastOps.contains(onRequest.request.op)) { genericLogic(forApproach)(onRequest) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K2.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K2.scala index c0d5c1f9..721f14c6 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K2.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemK/K2.scala @@ -13,7 +13,7 @@ import org.combinators.ep.generator.communication.{PotentialRequest, ReceivedReq import org.combinators.ep.generator.{ApproachImplementationProvider, EvolutionImplementationProvider} // Takes adapters for return in if-then-else, s.t. functional- and imperative-style if-then-else can be -// used in an uniform way. +// used in a uniform way. sealed class K2[P <: AnyParadigm, AIP[P <: AnyParadigm] <: ApproachImplementationProvider.WithParadigm[P], IfBlockType](val paradigm: P) { type IfThenElseCommand = (paradigm.syntax.Expression, diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemX/X1.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemX/X1.scala index cde088eb..b7926522 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemX/X1.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/eips/systemX/X1.scala @@ -122,7 +122,7 @@ object X1 { one <- forApproach.reify(InstanceRep(TypeRep.Double)(1.0)) - // Know you have add data type so you can construct it + // Know you have `Add` data type so you can construct it condExpr <- ffiArithmetic.arithmeticCapabilities.lt(one, ctrVar) stmt <- ffiImper.imperativeCapabilities.whileLoop(condExpr, for { res <- forApproach.instantiate(math.M0.getModel.baseDataType, math.M0.Add, resultVar, onRequest.request.arguments.head._2) diff --git a/domain/math/src/main/scala/org/combinators/ep/domain/math/systemO/O1OA.scala b/domain/math/src/main/scala/org/combinators/ep/domain/math/systemO/O1OA.scala index 6e6405a8..66e07a63 100644 --- a/domain/math/src/main/scala/org/combinators/ep/domain/math/systemO/O1OA.scala +++ b/domain/math/src/main/scala/org/combinators/ep/domain/math/systemO/O1OA.scala @@ -5,7 +5,7 @@ import org.combinators.ep.domain._ import org.combinators.ep.domain.math.M2 /** - * Combines together two different evolutions, each of which has an independent Op/TypeCase whose implementation + * Combines two different evolutions, each of which has an independent Op/TypeCase whose implementation * has been optimized, as declared by the EIP. */ object O1OA extends Evolution { diff --git a/dynamicProgramming/src/main/scala/org/combinators/README.md b/dynamicProgramming/src/main/scala/org/combinators/README.md new file mode 100644 index 00000000..88df9c76 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/README.md @@ -0,0 +1,13 @@ +The `EnhancedModel` adds additional capabilities to support generating various DP problems. + +``` +class EnhancedModel(val problem:String, + val input:Seq[ArgExpression], + val subproblemType:ArgumentType, // Type of solution + val solutionType:ArgumentType, // Type of return value + val solution:SubproblemInvocation, + val definition:Definition, + val answer:Definition, // all existing Expression should just use ExpressionDefinition(expr) + val mode:ProblemOrder = Canonical()) +``` + diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/README.md b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/README.md new file mode 100644 index 00000000..ed63a180 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/README.md @@ -0,0 +1,32 @@ +This `cogen` package contains the earliest attempts to use CoGen to generate dynamic programming (DP) solutions in Java. + +Starting from available Java implementations of numerous DP problems, in the initial stage of this project the goal was to be able +to replicate these code using straight CoGen code. Along the way, one hoped it would be possible to find opportunities to reuse +CoGen methods to be able to normalize the entire process. + +# Bottom Up + +* Pascal's Triangle +* One Sequence + - DecodeWays + - Fibonacci + - MaxSubArray + - Tribonacci +* Two Sequences + - LongestCommonSubSequence + - UncrossedLines + +# Top Down + +* Pascal's Triangle +* One Sequence + - Delete And Earn + - House Robber + - JumpTo + - Tribonacci + +# Summary + +While various DP problems can be generated through straight CoGen code, this approach is untenable and ultimately did not really result +in reusable methods for these problems. + diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/grid/pascalBU/PascalMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/grid/pascalBU/PascalMainJava.scala new file mode 100644 index 00000000..97b3df37 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/grid/pascalBU/PascalMainJava.scala @@ -0,0 +1,82 @@ +package org.combinators.archive.cogen.bottomUp.grid.pascalBU + +/** + * One of the earliest implementations to generate bottom-up implementation of Pascal's Triangle. + * + * The logic is faulty and doesn't work. This is an example of the difficulty in trying to manually + * write nested loop logic using straight cogen + * + * val targetDirectory = Paths.get("target", "pascalBU") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} + +import java.nio.file.{Path, Paths} + + +class PascalMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + + val dpApproach = PascalObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object PascalDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "pascalBU") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new PascalMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/grid/pascalBU/PascalObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/grid/pascalBU/PascalObjectOrientedProvider.scala new file mode 100644 index 00000000..3b9745ed --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/grid/pascalBU/PascalObjectOrientedProvider.scala @@ -0,0 +1,268 @@ +package org.combinators.archive.cogen.bottomUp.grid.pascalBU + +/** + * One of the earliest implementations to generate bottom-up implementation of Pascal's Triangle. + * + * The logic is faulty and doesn't work. This is an example of the difficulty in trying to manually + * write nested loop logic using straight cogen + * + * val targetDirectory = Paths.get("target", "pascalBU") + */ +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.TypeRep +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, NameProvider} +import org.combinators.dp.TestExample +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.dp.original.Utility +import org.combinators.models.{LiteralInt, UnitExpression} +import org.combinators.archive.unenhancedModels.models.LiteralPair + +trait PascalObjectOrientedProvider extends Utility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext,paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext,paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message:String = "message" + lazy val main:String = "main" + lazy val testName = names.mangle("TestSuite") + lazy val compute = names.mangle("compute") + + def getter(attr:String) : String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setParameters(Seq((names.mangle("r"), intType),(names.mangle("c"), intType))) + _ <- setReturnType(intType) + + } yield () + } + + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + import ooParadigm.methodBodyCapabilities._ + + for { + _ <- make_compute_method_signature() + args <- getArguments() + + ten <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 10) + + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + array2dType <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + (namer,tper,r) = args.head + (namec,tpec,c) = args.tail.head + rp1 <- arithmetic.arithmeticCapabilities.add(r, one) + cp1 <- arithmetic.arithmeticCapabilities.add(c, one) + instantiated <- array.arrayCapabilities.create(intType /* array2dType */, Seq(rp1, cp1), None) + dpName <- freshName(names.mangle("dp")) + dpVar <- impParadigm.imperativeCapabilities.declareVar(dpName, array2dType, Some(instantiated)) + + iName <- freshName(names.mangle("i")) + iVar <- impParadigm.imperativeCapabilities.declareVar(iName, intType, Some(zero)) + iVarPlusOne <- arithmetic.arithmeticCapabilities.add(iVar,one) + outerCond <- arithmetic.arithmeticCapabilities.lt(iVar, rp1) + outerLoop <-impParadigm.imperativeCapabilities.whileLoop(outerCond, + for { + jName <- freshName(names.mangle("j")) + jVar <- impParadigm.imperativeCapabilities.declareVar(jName, intType, Some(zero)) + innerCond <- arithmetic.arithmeticCapabilities.lt(jVar, iVar) + innerLoop <-impParadigm.imperativeCapabilities.whileLoop(innerCond, + for { + condExpr1 <- arithmetic.arithmeticCapabilities.le(jVar, zero) + condExpr2 <- arithmetic.arithmeticCapabilities.le(jVar, zero) + dpi <- array.arrayCapabilities.get(dpVar, Seq(iVar)) + dpj <- array.arrayCapabilities.get(dpi, Seq(jVar)) + + im1 <- arithmetic.arithmeticCapabilities.sub(iVar,one) + jm1 <- arithmetic.arithmeticCapabilities.sub(jVar,one) + jVarPlusOne <- arithmetic.arithmeticCapabilities.add(jVar,one) + dpim1 <-array.arrayCapabilities.get(dpVar, Seq(im1)) + dpim1jm1 <-array.arrayCapabilities.get(dpim1, Seq(jm1)) + dpim1j <-array.arrayCapabilities.get(dpim1, Seq(iVar)) + sum <- arithmetic.arithmeticCapabilities.add(dpim1j,dpim1jm1) + + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(condExpr1, + for { + assign <- impParadigm.imperativeCapabilities.assignVar(dpj, one) + + _ <- addBlockDefinitions(Seq(assign)) + } yield (), + Seq.empty, + Some(for{ + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(condExpr2, + for { + assign <- impParadigm.imperativeCapabilities.assignVar(dpj, zero) + _ <- addBlockDefinitions(Seq(assign)) + } yield (), + Seq.empty, + Some(for{ + assign <- impParadigm.imperativeCapabilities.assignVar(dpj, sum) + _ <- addBlockDefinitions(Seq(assign)) + }yield()) + ) + _ <- addBlockDefinitions(Seq(ifStmt)) + + }yield()) + ) + jPlusOne <- impParadigm.imperativeCapabilities.assignVar(jVar, jVarPlusOne) + _ <- addBlockDefinitions(Seq(ifStmt, jPlusOne)) + }yield()) + iPlusOne <- impParadigm.imperativeCapabilities.assignVar(iVar, iVarPlusOne) + _ <- addBlockDefinitions(Seq(innerLoop, iPlusOne)) + }yield()) + + dpr <- array.arrayCapabilities.get(dpVar, Seq(r)) + dprc <- array.arrayCapabilities.get(dpr, Seq(c)) + + _ <- addBlockDefinitions(Seq(outerLoop)) + + } yield Some(dprc) + } + /** + + public Integer compute(Integer r, Integer c) { + Integer[][] dp = new Integer[(r + 1)][(c + 1)]; + for(int i = 0;i + + val pair = example.inputType match { + case lp:LiteralPair => (lp.val1, lp.val2) + case _ => ??? + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + pascType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle("Pascal")) + r_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, pair._1) + c_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, pair._2) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(pascType, Seq.empty) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, compute) + + intType <- toTargetLanguageType(TypeRep.Int) + pascrc_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + pascrc_actual <- apply(computeMethod, Seq(r_value,c_value)) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, pascrc_actual, pascrc_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + def makeTestCase(clazzName:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestCase(), names.mangle(clazzName)) + } yield () + } + + def implement(): Generator[ProjectContext, Unit] = { + + for { + _ <- makeSimpleDP() + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(testName, makeTestCase("DP")) + ) + } yield () + } +} + +object PascalObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = PascalObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : PascalObjectOrientedProvider.WithParadigm[base.type] = + new PascalObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/OneSequencesUtility.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/OneSequencesUtility.scala new file mode 100644 index 00000000..5a57245f --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/OneSequencesUtility.scala @@ -0,0 +1,48 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence + +import org.combinators.cogen.TypeRep +import org.combinators.cogen.Command.Generator +import org.combinators.dp.original.Utility + +trait OneSequencesUtility extends Utility { + import paradigm._ + import syntax._ + + def format_if_else(iterator: Expression, input: (Expression, Statement)): (Generator[MethodBodyContext,Expression], Generator[MethodBodyContext,Unit]) = { + import paradigm.methodBodyCapabilities._ + + val cond = arithmetic.arithmeticCapabilities.le(iterator, input._1) + val body = for { + _ <- addBlockDefinitions(Seq(input._2)) + } yield () + (cond, body) + } + + def one_sequence_bottom_up(iterator: Expression, length: Expression, baseCases: Seq[(Expression, Statement)],relation: Statement): Generator[MethodBodyContext, Seq[Statement]] ={ + import paradigm.methodBodyCapabilities._ + import ooParadigm.methodBodyCapabilities._ + for { + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + condExpr <- arithmetic.arithmeticCapabilities.lt(iterator,length) + while_loop <- impParadigm.imperativeCapabilities.whileLoop(condExpr, for { + + ifCond1 <- arithmetic.arithmeticCapabilities.le(iterator, baseCases.head._1) + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(ifCond1, for { + _ <- addBlockDefinitions(Seq(baseCases.head._2)) //First Base Case + } yield (), + + Seq.empty, + //baseCases.tail.map(format_if_else), //Other Base Cases + + Some( + for { + _ <- addBlockDefinitions(Seq(relation)) //General Case + } yield ()) + ) + + incrStmt <- plus_equals(iterator, one) + _ <- addBlockDefinitions(Seq(ifStmt,incrStmt)) + } yield ()) + }yield(Seq(while_loop)) + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/decodeways/DecodeWaysMain.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/decodeways/DecodeWaysMain.scala new file mode 100644 index 00000000..02a61fe9 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/decodeways/DecodeWaysMain.scala @@ -0,0 +1,174 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.decodeways + +/** + * An early implementation with unenhanced model that never was completed. + * + * Generated DP solution does not work and test cases remain connected to Fibonacci. + * + * val targetDirectory = Paths.get("target", "decodeways") + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} +import org.combinators.models._ +import org.combinators.models.original.Model +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class DPMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = DecodeWaysProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement(model, option) // WRONG METHODs + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +/* + +import java.util.Arrays; + +class Solution { + // Memoization table initialized with -1 + private int[] memo; + + public int numDecodings(String s) { + if (s == null || s.length() == 0 || s.charAt(0) == '0') { + return 0; + } + memo = new int[s.length()]; + // Initialize memo array with -1 to indicate uncomputed states + Arrays.fill(memo, -1); + return decode(s, 0); + } + + private int decode(String s, int index) { + // Base case: If we reach the end of the string, we have found one valid decoding + if (index == s.length()) { + return 1; + } + // If the current character is '0', it cannot be a valid single digit and cannot + // start a two-digit number if it's the first digit, so return 0 ways + if (s.charAt(index) == '0') { + return 0; + } + // If the result for the current index is already computed, return it + if (memo[index] != -1) { + return memo[index]; + } + + int ways = 0; + // Option 1: Decode a single digit + ways += decode(s, index + 1); + + // Option 2: Decode a two-digit number if it is valid (between 10 and 26 inclusive) + if (index + 1 < s.length()) { + int twoDigit = Integer.parseInt(s.substring(index, index + 2)); + if (twoDigit >= 10 && twoDigit <= 26) { + ways += decode(s, index + 2); + } + } + + // Store the result in the memo table before returning + memo[index] = ways; + return ways; + } +} + + + */ + +@deprecated(message = "Generated code in Java does not compile.") +object DPDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "decodeways") + + def run(args: List[String]): IO[ExitCode] = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val ascii_zero:LiteralChar = LiteralChar('0') + val two: LiteralInt = LiteralInt(2) + + // what was passed into constructor of the original class + val input:InputExpression = InputExpression("s") // might also need to pass in "type" + + val bound = List(ArgExpression(0, "text1", StringType(), "r"), ArgExpression(1, "text2", StringType(), "c")) + + val r: IteratorExpression = IteratorExpression(0, "r") // only one argument, n + val c: IteratorExpression = IteratorExpression(1, "c") // only one argument, n + + val DecodeWays = new Model("DecodeWays", + bound, + cases = List( + // s.length() == n + ( Some(StringLengthExpression(input) == one), one ), + // s.CharAt(n) == '0') + ( Some(CharAtExpression(input, one) == ascii_zero), zero), + // HACK == helper(n-1) + ( None, SubproblemExpression(Seq(r - one))) + ) + ) + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new DPMainJava() } + _ <- IO { println("[OK]") } + + // pass in TOP DOWN + result <- main.runDirectToDisc(targetDirectory, DecodeWays, topDown) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/decodeways/DecodeWaysProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/decodeways/DecodeWaysProvider.scala new file mode 100644 index 00000000..695a0f7c --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/decodeways/DecodeWaysProvider.scala @@ -0,0 +1,121 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.decodeways + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, UnitExpression} + +@deprecated(message = "Generated code in Java does not compile.") +trait DecodeWaysProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + import ooParadigm._ + + // Specific examples hard coded for Int input and Int output + def makeTestsDecodeWays(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import paradigm.methodBodyCapabilities._ + import eqls.equalityCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("fib0", LiteralInt(0), LiteralInt(0), new UnitExpression), // for now, leave solution as None + new TestExample("fib1", LiteralInt(1), LiteralInt(1), new UnitExpression), + new TestExample("fib2", LiteralInt(2), LiteralInt(1), new UnitExpression), + new TestExample("fib7", LiteralInt(7), LiteralInt(13), new UnitExpression), + new TestExample("fib20", LiteralInt(20), LiteralInt(6765), new UnitExpression), + new TestExample("fib40", LiteralInt(40), LiteralInt(102334155), new UnitExpression) + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralInt => lt.literal + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + n_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, input_value) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(n_value)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestsDecodeWays(implementation), names.mangle("DP")) + } yield () + } +} + +object DecodeWaysProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): DecodeWaysProvider.WithParadigm[base.type] = + new DecodeWaysProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/fibtest/FibTestMain.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/fibtest/FibTestMain.scala new file mode 100644 index 00000000..39f0c9a0 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/fibtest/FibTestMain.scala @@ -0,0 +1,84 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.fibtest + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of Fibonacci with test cases. + * + * This showed the potential of writing pure CoGen code to handle all generators, though one can see how quickly this + * becomes inefficient: it is hard to imagine reusable blocks of code that could be reused across different DP solutions. + * + * val targetDirectory = Paths.get("target", "bottomUp", "oneSequence", "fibtest") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class FibTestMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + + val dpApproach = FibTestObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object FibTestDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "bottomUp", "oneSequence", "fibtest") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new FibTestMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/fibtest/FibTestObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/fibtest/FibTestObjectOrientedProvider.scala new file mode 100644 index 00000000..d150d161 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/fibtest/FibTestObjectOrientedProvider.scala @@ -0,0 +1,207 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.fibtest + +import org.combinators.archive.cogen.bottomUp.oneSequence.OneSequencesUtility +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.Utility + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of Fibonacci with test cases. + * + * Note that it attempted to use "one_sequence_bottom_up" but this method never fully worked with multiple sequences of base cases + */ +trait FibTestObjectOrientedProvider extends OneSequencesUtility with Utility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext,paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext,paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + res <- ooParadigm.methodBodyCapabilities.getMember(self, name) + } yield res + } + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message:String = "message" + lazy val main:String = "main" + lazy val testName = names.mangle("TestSuite") + + def getter(attr:String) : String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _ <- setParameters(Seq((names.mangle("num"), intType))) + _ <- setReturnType(intType) + + } yield () + } + + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + import ooParadigm.methodBodyCapabilities._ + for { + _ <- make_compute_method_signature() + args <- getArguments() + + func <- find_method_recursive(names.mangle("compute")) + + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + + two <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + (namen,tpen,num) = args.head + + np1 <- arithmetic.arithmeticCapabilities.add(num,one) + + //Instantiate + instantiated <- array.arrayCapabilities.create(intType /* arrayType*/, Seq(np1), None) + dpVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("dp"), arrayType, Some(instantiated)) + + //iterator + iName <- freshName(names.mangle("i")) + iVar <- impParadigm.imperativeCapabilities.declareVar(iName, intType, Some(zero)) + + //Base Cases + dpVarIndex <- array.arrayCapabilities.get(dpVar, Seq(iVar)) + bCase1 <- impParadigm.imperativeCapabilities.assignVar(dpVarIndex, iVar) + + //Relation + nm1 <-arithmetic.arithmeticCapabilities.sub(iVar,one) + nm2 <-arithmetic.arithmeticCapabilities.sub(iVar,two) + dpVarIndexnm1 <-array.arrayCapabilities.get(dpVar, Seq(nm1)) + dpVarIndexnm2 <-array.arrayCapabilities.get(dpVar, Seq(nm2)) + sum <- arithmetic.arithmeticCapabilities.add(dpVarIndexnm1,dpVarIndexnm2) + + relation <- impParadigm.imperativeCapabilities.assignVar(dpVarIndex, sum) + + //one sequence bottom up + while_loop <- one_sequence_bottom_up(iVar, np1, Seq((one, bCase1)), relation) + _ <- addBlockDefinitions(while_loop) + + //final element + dpVarIndexn <-array.arrayCapabilities.get(dpVar, Seq(num)) + + } yield Some(dpVarIndexn) + } + + + def makeSimpleDP(): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("compute"), make_compute_method()) + } yield None + } + + addClassToProject(makeClass, names.mangle("FibTest")) + } + + + def makeTestCase(): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + for { + solutionType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle("FibTest")) + d_0 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + d_1 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + d_2 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + d_9 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 9) + d_11 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 11) + d_89 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 89) + d_34 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 34) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solutionType, Seq.empty) + intType <- toTargetLanguageType(TypeRep.Int) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, names.mangle("compute")) + + solution_result <- apply(computeMethod, Seq(d_0)) + asserteq0 <- asserts.assertionCapabilities.assertEquals(intType, solution_result, d_0) + + solution_result <- apply(computeMethod, Seq(d_2)) + asserteq1 <- asserts.assertionCapabilities.assertEquals(intType, solution_result, d_1) + + solution_result <- apply(computeMethod, Seq(d_9)) + asserteq2 <- asserts.assertionCapabilities.assertEquals(intType, solution_result, d_34) + + solution_result <- apply(computeMethod, Seq(d_11)) + asserteq3 <- asserts.assertionCapabilities.assertEquals(intType, solution_result, d_89) + + } yield Seq(asserteq0,asserteq1,asserteq2,asserteq3) + } + + def makeTestCase(clazzName:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestCase(), names.mangle(clazzName)) + } yield () + } + + def implement(): Generator[ProjectContext, Unit] = { + + for { + _ <- makeSimpleDP() + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(testName, makeTestCase("DP")) + ) + } yield () + } +} + +object FibTestObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = FibTestObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : FibTestObjectOrientedProvider.WithParadigm[base.type] = + new FibTestObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/maxsubarray/MaxSubarrayMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/maxsubarray/MaxSubarrayMainJava.scala new file mode 100644 index 00000000..94ac1834 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/maxsubarray/MaxSubarrayMainJava.scala @@ -0,0 +1,81 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.maxsubarray + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of MaxSubArray with test cases. + * + * val targetDirectory = Paths.get("target", "bottomUp", "oneSequence", "maxsubarray") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class MaxSubarrayMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = MaxSubarrayObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object MaxSubarrayDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "bottomUp", "oneSequence", "maxsubarray") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new MaxSubarrayMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/maxsubarray/MaxSubarrayObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/maxsubarray/MaxSubarrayObjectOrientedProvider.scala new file mode 100644 index 00000000..60951c53 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/maxsubarray/MaxSubarrayObjectOrientedProvider.scala @@ -0,0 +1,253 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.maxsubarray + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.Utility +import org.combinators.models.{LiteralArray, LiteralInt} + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of MaxSubArray + * + * Successfully used "new_full_set_max" helper method which generated code to compute maximum inside while loop. + */ +trait MaxSubarrayObjectOrientedProvider extends Utility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext,paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext,paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + res <- ooParadigm.methodBodyCapabilities.getMember(self, name) + } yield res + } + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message:String = "message" + lazy val main:String = "main" + lazy val testName = names.mangle("TestSuite") + + def getter(attr:String) : String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _ <- setParameters(Seq((names.mangle("nums"), arrayType))) + _ <- setReturnType(intType) + + } yield () + } + + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + _ <- make_compute_method_signature() + args <- getArguments() + + func <- find_method_recursive(names.mangle("compute")) + + intType <- toTargetLanguageType(TypeRep.Int) + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + (namen,tpen,nums) = args.head + + // manually create variables 'c', 'm', 'i' to use + currentName <- freshName(names.mangle("c")) + numsZ <- array.arrayCapabilities.get(nums, Seq(zero)) + currentVar <- impParadigm.imperativeCapabilities.declareVar(currentName, intType, Some(numsZ)) + + maxName <- freshName(names.mangle("m")) + maxVar <- impParadigm.imperativeCapabilities.declareVar(maxName, intType, Some(currentVar)) + + iName <- freshName(names.mangle("i")) + iVar <- impParadigm.imperativeCapabilities.declareVar(iName, intType, Some(one)) + + numsLength <- ooParadigm.methodBodyCapabilities.getMember(nums, names.mangle("length")) + whileCond <- arithmetic.arithmeticCapabilities.lt(iVar,numsLength) + + init_stmt <- impParadigm.imperativeCapabilities.whileLoop(whileCond, for { + + // the BODY + curIfStmt <- set_max(currentVar,zero) + + //Current assignment + numsI <- array.arrayCapabilities.get(nums, Seq(iVar)) + currentAssign <- plus_equals(currentVar,numsI) + + //Set Max + maxIfStmt <- new_full_set_max(maxVar,maxVar, currentVar) + + // last line to be added to the while loop + //incrExpr <- arithmetic.arithmeticCapabilities.add(iVar, one) + incrStmt <- plus_equals(iVar, one) + _ <- addBlockDefinitions(Seq(curIfStmt, currentAssign)++maxIfStmt++Seq( incrStmt)) + } yield () + ) + _ <- addBlockDefinitions(Seq(init_stmt)) + + } yield Some(maxVar) + } +/** ACTUAL JAVA IMPLEMENTATION AS CODED MANUALLY. USE AS REFERENCE + class MaxSubarray { + public int solution(int[] nums) { + + int c=nums[0]; + int m=c; + + for(int i=1;i + + val array_vals = example.inputType match { + case la:LiteralArray => la.literal + case _ => ??? + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + expr <- create_int_array(array_vals) + variable <- impParadigm.imperativeCapabilities.declareVar(names.mangle(example.name), arrayType, Some(expr)) + invoke <- apply(computeMethod, Seq(variable)) + solution <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + assert_stmt <- asserts.assertionCapabilities.assertEquals(arrayType, invoke, solution) + + // still need test case for validating full_solution when calling 'retrieve()' + + } yield assert_stmt + } + } yield assert_statements + } + + def makeTestCase(clazzName:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestCase(), names.mangle(clazzName)) + } yield () + } + + def implement(): Generator[ProjectContext, Unit] = { + + for { + _ <- makeSimpleDP() + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(testName, makeTestCase("DP")) + ) + } yield () + } +} + +object MaxSubarrayObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = MaxSubarrayObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn : Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : MaxSubarrayObjectOrientedProvider.WithParadigm[base.type] = + new MaxSubarrayObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/tribonacci/TribonacciMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/tribonacci/TribonacciMainJava.scala new file mode 100644 index 00000000..2f3b1604 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/tribonacci/TribonacciMainJava.scala @@ -0,0 +1,84 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.tribonacci + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of Tribonacci BUT no test cases. + * + * This showed the potential of writing pure CoGen code to handle all generators, though one can see how quickly this + * becomes inefficient: it is hard to imagine reusable blocks of code that could be reused across different DP solutions. + * + * val targetDirectory = Paths.get("target", "bottomUp", "oneSequence", "tribonacci") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class TribonacciMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + + val dpApproach = TribonacciObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object TribonacciDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "bottomUp", "oneSequence", "tribonacci") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new TribonacciMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/tribonacci/TribonacciObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/tribonacci/TribonacciObjectOrientedProvider.scala new file mode 100644 index 00000000..2e5b489a --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/oneSequence/tribonacci/TribonacciObjectOrientedProvider.scala @@ -0,0 +1,238 @@ +package org.combinators.archive.cogen.bottomUp.oneSequence.tribonacci + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, Command, NameProvider, TypeRep} +import org.combinators.dp.original.Utility + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of Tribonacci with test cases. + * + * This showed the potential of writing pure CoGen code to handle all generators, though one can see how quickly this + * becomes inefficient: it is hard to imagine reusable blocks of code that could be reused across different DP solutions. + * + * val targetDirectory = Paths.get("target", "bottomUp", "oneSequence", "tribonacci") + */ +trait TribonacciObjectOrientedProvider extends Utility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + import ooParadigm._ + + lazy val message: String = "message" + lazy val main: String = "main" + lazy val testName = names.mangle("TestSuite") + + def getter(attr: String): String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setParameters(Seq((names.mangle("n"), intType))) + _ <- setReturnType(intType) + + } yield () + } + + /** + * public class Solution { + * public int compute(int n) { + * if (n == 0) { + * return 0; + * } else if (n <= 2) { + * return 1; + * } else { + * int[] dp = new int[n + 1]; + * dp[0] = 0; + * dp[1] = 1; + * dp[2] = 1; + * + * int i = 3; + * while (i <= n) { + * dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]; + * i = i + 1; + * } + * } + * + * return dp[n]; + * } + * } + */ + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + import ooParadigm.methodBodyCapabilities._ + + for { + _ <- make_compute_method_signature() + args <- getArguments() + + (name, tpe, n) = args.head + + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + two <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + three <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 3) + + resultVar <- declare_and_inst_variable("result", intType, zero) + + // n <= 0 todo: replace le with eq + len0 <- arithmetic.arithmeticCapabilities.le(n, zero) + + // n <= 2 + len2 <- arithmetic.arithmeticCapabilities.le(n, two) + + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(len0, + for { + returnStmt <- impParadigm.imperativeCapabilities.returnStmt(zero) + _ <- addBlockDefinitions(Seq(returnStmt)) + } yield (), + Seq( + (len2, + for { + returnStmt <- impParadigm.imperativeCapabilities.returnStmt(one) + _ <- addBlockDefinitions(Seq(returnStmt)) + } yield () + ) + ), + + Some( + for { + // int[] dp = new int[n + 1]; + nValuePlusOne <- arithmetic.arithmeticCapabilities.add(n, one) + instantiated <- array.arrayCapabilities.create(intType /* arrayType*/, Seq(nValuePlusOne), None) + dpVar <- declare_and_inst_variable("dp", arrayType, instantiated) + + // dp[0] = 0; + dpVar0 <- array.arrayCapabilities.get(dpVar, Seq(zero)) + baseCase0 <- impParadigm.imperativeCapabilities.assignVar(dpVar0, zero) + _ <- addBlockDefinitions(Seq(baseCase0)) + + // dp[1] = 1; + dpVar1 <- array.arrayCapabilities.get(dpVar, Seq(one)) + baseCase1 <- impParadigm.imperativeCapabilities.assignVar(dpVar1, one) + _ <- addBlockDefinitions(Seq(baseCase1)) + + + // dp[2] = 1; + dpVar2 <- array.arrayCapabilities.get(dpVar, Seq(two)) + baseCase2 <- impParadigm.imperativeCapabilities.assignVar(dpVar2, one) + _ <- addBlockDefinitions(Seq(baseCase2)) + + iVar <- declare_and_inst_variable("i", intType, three) + + condExpr <- arithmetic.arithmeticCapabilities.le(iVar, n) + + // BUILD this up and then insert + emptyStmts <- for { + _ <- Command.skip[paradigm.MethodBodyContext] + + } yield Seq.empty + + optimization_body <- for { + // dp[i - 1] + dpi_1 <- arithmetic.arithmeticCapabilities.sub(iVar, one) + dpi_1val <- array.arrayCapabilities.get(dpVar, Seq(dpi_1)) + + // dp[i - 2] + dpi_2 <- arithmetic.arithmeticCapabilities.sub(iVar, two) + dpi_2val <- array.arrayCapabilities.get(dpVar, Seq(dpi_2)) + + // dp[i - 3] + dpi_3 <- arithmetic.arithmeticCapabilities.sub(iVar, three) + dpi_3val <- array.arrayCapabilities.get(dpVar, Seq(dpi_3)) + + // dp[n] = dp[n - 1] + dp[n - 2] + dp[n - 3]; + dpi <- array.arrayCapabilities.get(dpVar, Seq(iVar)) + dpival <- arithmetic.arithmeticCapabilities.add(dpi_1val, dpi_2val) + dpival <- arithmetic.arithmeticCapabilities.add(dpival, dpi_3val) + dpiAssign <- impParadigm.imperativeCapabilities.assignVar(dpi, dpival) + } yield Seq(dpiAssign) + + buildUp <- make_for_loop(iVar, condExpr, optimization_body) + + _ <- addBlockDefinitions(Seq(buildUp)) + + dpn <- array.arrayCapabilities.get(dpVar, Seq(n)) + + returnStmt <- impParadigm.imperativeCapabilities.returnStmt(dpn) + _ <- addBlockDefinitions(Seq(returnStmt)) + } yield () + ) + ) + _ <- addBlockDefinitions(Seq(ifStmt)) + + } yield None + } + + def makeSimpleDP(): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("compute"), make_compute_method()) + } yield None + } + + addClassToProject(makeClass, names.mangle("Tribonacci")) + } + + def implement(): Generator[ProjectContext, Unit] = { + + for { + _ <- makeSimpleDP() + } yield None + } +} + +object TribonacciObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = TribonacciObjectOrientedProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : TribonacciObjectOrientedProvider.WithParadigm[base.type] = + new TribonacciObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/TwoSequencesUtility.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/TwoSequencesUtility.scala new file mode 100644 index 00000000..0f7a1fc4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/TwoSequencesUtility.scala @@ -0,0 +1,102 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences + +import org.combinators.cogen.TypeRep +import org.combinators.cogen.Command.Generator +import org.combinators.dp.original.Utility + +/** + * Helper methods to deal with DP problems that involve two sequences. + * + * This was one of the earliest attempts to create helper methods to generate individual elements of a DP solution. + */ +trait TwoSequencesUtility extends Utility { + import paradigm._ + import syntax._ + + def make_solution(len1: Expression, len2: Expression, dp: Expression, r: Expression, c: Expression, optimizationBody: Statement): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + import ooParadigm.methodBodyCapabilities._ + + // assumes that the base cases are the same for both sequences + def make_base_cases(rowVar: Expression, rowGuard: Expression, rowUpdate: Expression, + colVar: Expression, colGuard: Expression, colUpdate: Expression, + relation: Expression): Generator[MethodBodyContext, Seq[Statement]] = { + + for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + dp_row_0 <- get_matrix_element(dp, rowVar, zero) + row_relation <- impParadigm.imperativeCapabilities.assignVar(dp_row_0, relation) + + dp_0_col <- get_matrix_element(dp, zero, colVar) + col_relation <- impParadigm.imperativeCapabilities.assignVar(dp_0_col, relation) + + len1_base_case <- make_for_loop(rowVar, rowGuard, rowUpdate, Seq(row_relation)) + len2_base_case <- make_for_loop(colVar, colGuard, colUpdate, Seq(col_relation)) + } yield Seq(len1_base_case, len2_base_case) + } + + def make_optimization_step(guard1: Expression, update1: Expression, + guard2: Expression, update2: Expression): Generator[MethodBodyContext, Statement] = { + + for { + while_loop <- make_nested_for_loop(r, guard1, update1, c, guard2, update2, Seq(optimizationBody), Seq.empty) + } yield while_loop + } + + for { + stringType <- toTargetLanguageType(TypeRep.String) + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + array2dType <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + // base cases + // todo: figure out how to differentiate between integer and string to use the correct length method/attribute + rBaseCase <- declare_and_inst_variable("rBaseCase", intType, zero) + rBaseCase_guard <- arithmetic.arithmeticCapabilities.le(rBaseCase, len1) + rBaseCase_update <- arithmetic.arithmeticCapabilities.add(rBaseCase, one) + + cBaseCase <- declare_and_inst_variable("cBaseCase", intType, zero) + cBaseCase_guard <- arithmetic.arithmeticCapabilities.le(cBaseCase, len2) + cBaseCase_update <- arithmetic.arithmeticCapabilities.add(cBaseCase, one) + + test_stmt <- impParadigm.imperativeCapabilities.assignVar(rBaseCase, zero) + + base_cases <- make_base_cases(rBaseCase, rBaseCase_guard, rBaseCase_update, cBaseCase, cBaseCase_guard, cBaseCase_update, zero) + _ <- addBlockDefinitions(base_cases) + + // optimization step + r_guard <- arithmetic.arithmeticCapabilities.lt(r, len1) + r_update <- arithmetic.arithmeticCapabilities.add(r, one) + + c_guard <- arithmetic.arithmeticCapabilities.lt(c, len2) + c_update <- arithmetic.arithmeticCapabilities.add(c, one) + + optimization_step <- make_optimization_step(r_guard, r_update, c_guard, c_update) + _ <- addBlockDefinitions(Seq(optimization_step)) + + return_stmt <- get_bottom_right_dp_element(dp, len1, len2) + } yield Option(return_stmt) + } + + def instantiate_dp(numRows: Expression, numCols: Expression): Generator[MethodBodyContext, Expression] = { + import paradigm.methodBodyCapabilities._ + + for { + array2dType <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + intType <- toTargetLanguageType(TypeRep.Int) + instantiated <- array.arrayCapabilities.create(intType /* array2dType*/, Seq(numRows, numCols), None) + + dpVar <- declare_and_inst_variable("dp", array2dType, instantiated) + } yield dpVar + } + + def get_bottom_right_dp_element(dp: Expression, len1: Expression, len2: Expression): Generator[MethodBodyContext, Expression] = { + + for { + dpBottomRight <- get_matrix_element(dp, len1, len2) + } yield dpBottomRight + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LCSMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LCSMainJava.scala new file mode 100644 index 00000000..5f85763d --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LCSMainJava.scala @@ -0,0 +1,95 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences.longestCommonSubsequence + +/** + * One of the earliest implementations to generate bottom-up implementation of Longest Common Subsequence + * + * val targetDirectory = Paths.get("target", "pascalBU") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.twoSequences.LongestCommonSubsequenceModel +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class LCSMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = LCSProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def filesToGenerate(model:Model, option:GenerationOption):Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + IO { + println("Computing Files...") + val computed = filesToGenerate(model, option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + println(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + println("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object LCSDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "lcs") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val LCS = new LongestCommonSubsequenceModel().instantiate() + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new LCSMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, LCS, topDownWithMemo) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LCSProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LCSProvider.scala new file mode 100644 index 00000000..1d9dd8c1 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LCSProvider.scala @@ -0,0 +1,121 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences.longestCommonSubsequence + +import org.combinators.archive.unenhancedModels.models.LiteralStringPair +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, LiteralString} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait LCSProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTestsLCS(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("fib0", LiteralStringPair("ACTG", "CGATC"), LiteralInt(2), LiteralString("AC")) // for now, leave solution as None + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralStringPair => (lt.string1, lt.string2) + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + s1_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._1) + s2_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._2) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(s1_value, s2_value)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestsLCS(implementation), names.mangle("DP")) + } yield () + } +} + +object LCSProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): LCSProvider.WithParadigm[base.type] = + new LCSProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LongestCommonSubsequenceMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LongestCommonSubsequenceMainJava.scala new file mode 100644 index 00000000..0d765114 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LongestCommonSubsequenceMainJava.scala @@ -0,0 +1,80 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences.longestCommonSubsequence + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} + +import java.nio.file.{Path, Paths} + +/** + * One of the earliest attempts to generate bottom-up implementation of Longest Common Subsequence + * + * Code generates doesn't work, since the "make_solution" doesn't accurately generate nested loops properly. + * + * val targetDirectory = Paths.get("target", "lcs") + */ +class LongestCommonSubsequenceMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = LongestCommonSubsequenceObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object LongestCommonSubsequenceDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "lcs") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new LongestCommonSubsequenceMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LongestCommonSubsequenceObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LongestCommonSubsequenceObjectOrientedProvider.scala new file mode 100644 index 00000000..c69ed5bb --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/longestCommonSubsequence/LongestCommonSubsequenceObjectOrientedProvider.scala @@ -0,0 +1,266 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences.longestCommonSubsequence + +import org.combinators.archive.cogen.bottomUp.twoSequences.TwoSequencesUtility +import org.combinators.archive.unenhancedModels.models.LiteralStringPair +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, Command, NameProvider, TypeRep} +import org.combinators.models.* + +/** + * One of the earliest attempts to generate bottom-up implementation of Longest Common Subsequence + * + * Code generates doesn't work, since the "make_solution" doesn't accurately generate nested loops properly. + */ +trait LongestCommonSubsequenceObjectOrientedProvider extends TwoSequencesUtility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type ] + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message: String = "message" + lazy val main: String = "main" + lazy val testName = names.mangle("TestSuite") + + def getter(attr: String): String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + stringType <- toTargetLanguageType(TypeRep.String) + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setParameters(Seq((names.mangle("s1"), stringType), (names.mangle("s2"), stringType))) + _ <- setReturnType(intType) + } yield () + } + + // public class LongestCommonSubsequence { + // public int solution(String s1, String s2) { + // /** + // * Initialization + // */ + // int len1 = s1.length(); + // int len2 = s2.length(); + // + // int[][] dp = new int[len1 + 1][len2 + 1]; + // + // /** + // * Iterative solution + // */ + // for(int r = 0; r < len1; r++) { + // for(int c = 0; c < len2; c++) { + // if(s1.charAt(r) == s2.charAt(c)) { + // dp[r + 1][c + 1] = dp[r][c] + 1; + // } else { + // dp[r + 1][c + 1] = Math.max(dp[r][c + 1], dp[r + 1][c]); + // } + // } + // } + // + // /** + // * Return bottom right element + // */ + // return dp[len1][len2]; + // } + // } + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + stringType <- toTargetLanguageType(TypeRep.String) + charType <- toTargetLanguageType(TypeRep.Char) + intType <- toTargetLanguageType(TypeRep.Int) + array2dType <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + _ <- make_compute_method_signature() + + args <- getArguments() + + (names1, tpes1, s1) = args.head + (names2, tpes2, s2) = args.tail.head + + /** + * initialization + */ + s1Length <- ooParadigm.methodBodyCapabilities.getMember(s1, names.mangle("length")) + len1 <- declare_and_inst_variable("len1", intType, apply(s1Length, Seq.empty)) + len1PlusOne <- arithmetic.arithmeticCapabilities.add(len1, one) + + s2Length <- ooParadigm.methodBodyCapabilities.getMember(s2, names.mangle("length")) + len2 <- declare_and_inst_variable("len2", intType, apply(s2Length, Seq.empty)) + len2PlusOne <- arithmetic.arithmeticCapabilities.add(len2, one) + +// instantiated <- ooParadigm.methodBodyCapabilities.instantiateObject( +// array2dType, +// Seq(len1PlusOne, len2PlusOne), +// None +// ) + instantiated <- array.arrayCapabilities.create(intType /* array2dType*/, Seq(len1PlusOne, len2PlusOne), None) + + dp <- declare_and_inst_variable("dp", array2dType, instantiated) + + /** + * optimization step definition + */ + r <- declare_and_inst_variable("r", intType, zero) + c <- declare_and_inst_variable("c", intType, zero) + + s1_charAt_r <- char_at(s1, r) + s2_charAt_c <- char_at(s2, c) + + optimization_condition <- eqls.equalityCapabilities.areEqual(charType, s1_charAt_r, s2_charAt_c) + optimization_body <- impParadigm.imperativeCapabilities.ifThenElse( + optimization_condition, + for { + rPlus1 <- arithmetic.arithmeticCapabilities.add(r, one) + cPlus1 <- arithmetic.arithmeticCapabilities.add(c, one) + + dpOfr1c1 <- get_matrix_element(dp, rPlus1, cPlus1) + + dpOfrc <- get_matrix_element(dp, r, c) + dpOfrc_PlusOne <- arithmetic.arithmeticCapabilities.add(dpOfrc, one) + + assignStmt <- impParadigm.imperativeCapabilities.assignVar(dpOfr1c1, dpOfrc_PlusOne) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty, + Some( + for { + _ <- Command.skip[paradigm.MethodBodyContext] + } yield () + ) + ) + + /** + * solution generation + */ + solution <- make_solution(len1, len2, dp, r, c, optimization_body) + + } yield solution + } + + def makeSimpleDP(): Generator[ProjectContext, Unit] = { + + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("compute"), make_compute_method()) + } yield None + } + + addClassToProject(makeClass, names.mangle("LongestCommonSubsequence")) + } + + def makeTestCase(): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + import AnyParadigm.syntax._ + + // https://en.wikipedia.org/wiki/Maximum_subarray_problem + val wiki_test = new TestExample("wiki", + LiteralStringPair("GAC", "AGCAT"), + LiteralInt(2), + LiteralString("GA") + ) + + for { + solutionType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle("LongestCommonSubsequence")) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solutionType, Seq.empty) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, names.mangle("compute")) + + assert_statements <- forEach(Seq(wiki_test)) { example => + + val strings = example.inputType match { + case lsp:LiteralStringPair => (lsp.string1, lsp.string2) + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + s1 <- paradigm.methodBodyCapabilities.reify(TypeRep.String, strings._1) + s2 <- paradigm.methodBodyCapabilities.reify(TypeRep.String, strings._2) + + invoke <- apply(computeMethod, Seq(s1, s2)) + solution <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + assert_stmt <- asserts.assertionCapabilities.assertEquals(arrayType, invoke, solution) + + // still need test case for validating full_solution when calling 'retrieve()' + + } yield assert_stmt + } + } yield assert_statements + } + + def makeTestCase(clazzName:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestCase(), names.mangle(clazzName)) + } yield () + } + + def implement(): Generator[ProjectContext, Unit] = { + + for { + _ <- makeSimpleDP() + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(testName, makeTestCase("DP")) + ) + } yield () + } +} + +object LongestCommonSubsequenceObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = LongestCommonSubsequenceObjectOrientedProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : LongestCommonSubsequenceObjectOrientedProvider.WithParadigm[base.type] = + new LongestCommonSubsequenceObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/uncrossedLines/UncrossedLinesMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/uncrossedLines/UncrossedLinesMainJava.scala new file mode 100644 index 00000000..708e7cc4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/uncrossedLines/UncrossedLinesMainJava.scala @@ -0,0 +1,78 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences.uncrossedLines + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} + +import java.nio.file.{Path, Paths} + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of UncrossedLines but NO TEST cases + * + * val targetDirectory = Paths.get("target", "uncrossedlines") + */ +class UncrossedLinesMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + + val dpApproach = UncrossedLinesObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object UncrossedLinesDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "uncrossedlines") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new UncrossedLinesMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/uncrossedLines/UncrossedLinesObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/uncrossedLines/UncrossedLinesObjectOrientedProvider.scala new file mode 100644 index 00000000..70573589 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/bottomUp/twoSequences/uncrossedLines/UncrossedLinesObjectOrientedProvider.scala @@ -0,0 +1,203 @@ +package org.combinators.archive.cogen.bottomUp.twoSequences.uncrossedLines + +import org.combinators.archive.cogen.bottomUp.twoSequences.TwoSequencesUtility +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, Command, NameProvider, TypeRep} + +/** + * One of the earliest implementations to generate a successful bottom-up implementation of UncrossedLines (no test cases however). + * + * Uses the "get_bottom_right_dp_element" methods in TwoSequencesUtility and "make_nested_for_loop" in Utility + */ +trait UncrossedLinesObjectOrientedProvider extends TwoSequencesUtility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message: String = "message" + lazy val main: String = "main" + lazy val testName = names.mangle("TestSuite") + + def getter(attr: String): String = { + "get" + attr.capitalize + } + + /** + * Defines the signature of the Uncrossed Lines solution method: + * Uncrossed Lines takes in two integer arrays `nums1` and `nums2` and returns an integer + * representing the number of uncrossed lines. + * + * @return a generator of unit, which represents the instructions to add the method signature to the class. + * Rather than returning something, this function + * is used to add the method signature to the class in place. + */ + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + intType <- toTargetLanguageType(TypeRep.Int) + + _ <- setParameters(Seq((names.mangle("nums1"), arrayType), (names.mangle("nums2"), arrayType))) + _ <- setReturnType(intType) + } yield () + } + + // todo: figure out how to use this + def initialize(): Generator[paradigm.MethodBodyContext, Seq[Expression]] = { + + for { + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + + dp <- instantiate_dp(one, one) + } yield Seq(dp, one) + } + + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + _ <- make_compute_method_signature() + args <- getArguments() + + (names1, tpes1, nums1) = args.head + (names2, tpes2, nums2) = args.tail.head + + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + array2dType <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + /** + * initialization + */ + len1Value <- ooParadigm.methodBodyCapabilities.getMember(nums1, names.mangle("length")) + len2Value <- ooParadigm.methodBodyCapabilities.getMember(nums2, names.mangle("length")) + len1 <- declare_and_inst_variable("len1", intType, len1Value) + len2 <- declare_and_inst_variable("len2", intType, len2Value) + + len1PlusOne <- arithmetic.arithmeticCapabilities.add(len1, one) + len2PlusOne <- arithmetic.arithmeticCapabilities.add(len2, one) + + dp <- instantiate_dp(len1PlusOne, len2PlusOne) + + r <- declare_and_inst_variable("r", intType, zero) + c <- declare_and_inst_variable("c", intType, zero) + + /** + * optimization + */ + outer_guard <- arithmetic.arithmeticCapabilities.lt(r, len1) + outer_update <- arithmetic.arithmeticCapabilities.add(r, one) + + inner_guard <- arithmetic.arithmeticCapabilities.lt(c, len2) + inner_update <- arithmetic.arithmeticCapabilities.add(c, one) + + nums1OfR <- array.arrayCapabilities.get(nums1, Seq(r)) + nums2OfC <- array.arrayCapabilities.get(nums2, Seq(c)) + + // todo: replace lt with equals or a substitute for equals + optimization_condition <- arithmetic.arithmeticCapabilities.lt(nums1OfR, nums2OfC) + body <- impParadigm.imperativeCapabilities.ifThenElse(optimization_condition, + for { + rPlus1 <- arithmetic.arithmeticCapabilities.add(r, one) + cPlus1 <- arithmetic.arithmeticCapabilities.add(c, one) + + dpOfr1c1 <- get_matrix_element(dp, rPlus1, cPlus1) + + dpOfrc <- get_matrix_element(dp, r, c) + dpOfrc_PlusOne <- arithmetic.arithmeticCapabilities.add(dpOfrc, one) + + assignStmt <- impParadigm.imperativeCapabilities.assignVar(dpOfr1c1, dpOfrc_PlusOne) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty, + Some( + for { + _ <- Command.skip[paradigm.MethodBodyContext] + } yield () + ) + ) + + empty <- for { + _ <- Command.skip[paradigm.MethodBodyContext] + } yield Seq.empty + + optimization <- make_nested_for_loop(r, outer_guard, outer_update, c, inner_guard, inner_update, Seq(body), empty) + _ <- addBlockDefinitions(Seq(optimization)) + + /** + * return the bottom right element + */ + dpBottomRight <- get_bottom_right_dp_element(dp, len1, len2) + } yield Some(dpBottomRight) + } + + def make_class(): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + + for { + _ <- addMethod(names.mangle("compute"), make_compute_method()) + } yield None + } + + addClassToProject(makeClass, names.mangle("UncrossedLines")) + } + + def implement(): Generator[ProjectContext, Unit] = { + for { + _ <- make_class() + } yield () + } +} + +object UncrossedLinesObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = UncrossedLinesObjectOrientedProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ): UncrossedLinesObjectOrientedProvider.WithParadigm[base.type] = + new UncrossedLinesObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/DeleteAndEarn/DeleteAndEarnMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/DeleteAndEarn/DeleteAndEarnMainJava.scala new file mode 100644 index 00000000..653b295f --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/DeleteAndEarn/DeleteAndEarnMainJava.scala @@ -0,0 +1,77 @@ +package org.combinators.archive.cogen.topDown.oneSequence.DeleteAndEarn + +/** + * One of the earliest implementations to attempt to solve DeleteAndEarn but NO TESTS + * + * Contains code to generate BubbleSort + * + * val targetDirectory = Paths.get("target", "DeleteAndEarn") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} + +import java.nio.file.{Path, Paths} + +class DeleteAndEarnMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + val jtApproach = DeleteAndEarnObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + + _ <- jtApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object DeleteAndEarnDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "DeleteAndEarn") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new DeleteAndEarnMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/DeleteAndEarn/DeleteAndEarnObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/DeleteAndEarn/DeleteAndEarnObjectOrientedProvider.scala new file mode 100644 index 00000000..4d6b3929 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/DeleteAndEarn/DeleteAndEarnObjectOrientedProvider.scala @@ -0,0 +1,358 @@ +package org.combinators.archive.cogen.topDown.oneSequence.DeleteAndEarn + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen._ +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.Booleans.WithBase +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality} +import org.combinators.cogen.paradigm.{ AnyParadigm, ObjectOriented} +import org.combinators.cogen.NameProvider + +/** + * One of the earliest implementations to attempt to solve DeleteAndEarn. + * + * Contains code to generate BubbleSort (though doesn't compile) + */ +trait DeleteAndEarnObjectOrientedProvider { + val paradigm: AnyParadigm + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + res <- ooParadigm.methodBodyCapabilities.getMember(self, name) + } yield res + } + + def makeHelperSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for{ + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _<- setParameters( + Seq((names.mangle("arr"), arrayType)) + ) + _<- setReturnType(arrayType) + } yield() + } + + def makeDeleteAndEarnSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for{ + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _<- setParameters( + Seq((names.mangle("arr"), arrayType), + (names.mangle("index"), intType)) + ) + _<- setReturnType(intType) + } yield() + } + + def makeSolutionSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for{ + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _<- setParameters( + Seq((names.mangle("arr"), arrayType)) + ) + _<- setReturnType(intType) + } yield() + } + + /* + public void bubbleSort(int[] array) { + boolean swapped = true; + int j = 0; + int tmp; + while (swapped) { + swapped = false; + j++; + for (int i = 0; i < array.length - j; i++) { + if (array[i] > array[i + 1]) { + tmp = array[i]; + array[i] = array[i + 1]; + array[i + 1] = tmp; + swapped = true; + } + } + } + } + */ + + def Bubble_sort(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + boo_true <- paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, true) + boo_false <- paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, false) + _<- makeHelperSignature() + args <- getArguments() + (namen,tpen,arr) = args.head + intType <- toTargetLanguageType(TypeRep.Int) + booleanType <- toTargetLanguageType(TypeRep.Boolean) + size <- array.arrayCapabilities.length(arr, Seq.empty) + + swapped <- impParadigm.imperativeCapabilities.declareVar(names.mangle("swapped"), booleanType, Some(boo_true)) + jVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("j"), intType, Some(zero)) + tmp <- impParadigm.imperativeCapabilities.declareVar(names.mangle("tmp"), intType, Some(zero)) + whileStmt <- impParadigm.imperativeCapabilities.whileLoop(swapped, for{ + swap_fal <- impParadigm.imperativeCapabilities.assignVar(swapped, boo_false) + _<-addBlockDefinitions(Seq(swap_fal)) + + j_one <- arithmetic.arithmeticCapabilities.add(jVar, one) + jVarExp <- impParadigm.imperativeCapabilities.assignVar(jVar, j_one) + _<-addBlockDefinitions(Seq(jVarExp)) + + index <- impParadigm.imperativeCapabilities.declareVar(names.mangle("i"), intType, Some(zero)) + arrSize_j <- arithmetic.arithmeticCapabilities.sub(size, jVar) + for_cond <- arithmetic.arithmeticCapabilities.lt(index, arrSize_j) + index_plusOne <- arithmetic.arithmeticCapabilities.add(index, one) + inner_forLoop <- impParadigm.imperativeCapabilities.whileLoop(for_cond, for{ + arr_index <- array.arrayCapabilities.get(arr, Seq(index)) + arr_index_one <- array.arrayCapabilities.get(arr, Seq(index_plusOne)) + inner_ifCond <- arithmetic.arithmeticCapabilities.lt(arr_index_one, arr_index) + + innerIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(inner_ifCond, for{ + assignTMP <- impParadigm.imperativeCapabilities.assignVar(tmp, arr_index) + assignArrIndex <- impParadigm.imperativeCapabilities.assignVar(arr_index, arr_index_one) + assignArrOneIndex <- impParadigm.imperativeCapabilities.assignVar(arr_index_one, arr_index) + swap_true <- impParadigm.imperativeCapabilities.assignVar(swapped, boo_true) + _<-addBlockDefinitions(Seq(assignTMP, assignArrIndex, assignArrOneIndex, swap_true)) + + } yield(), + Seq.empty) + _<-addBlockDefinitions(Seq(innerIfStmt)) + + } yield()) + _<- addBlockDefinitions(Seq(inner_forLoop)) + } yield()) + _<-addBlockDefinitions(Seq(whileStmt)) + + + } yield(Some(arr)) + } + + /* + private int dfs(int[] nums, int i) { + if (i >= nums.length) return 0; + + int cur = nums[i], pick = 0; + while (i < nums.length && nums[i] == cur) { + pick += nums[i]; + i++; + } + + int res = dfs(nums, i); + while (i < nums.length && nums[i] == cur + 1) { + i++; + } + + res = Math.max(res, pick + dfs(nums, i)); + return res; + } + */ + def helper(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + _ <- makeDeleteAndEarnSignature() + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + args <- getArguments() + intType <- toTargetLanguageType(TypeRep.Int) + (names1, tpes1, arr) = args.head + (names2, tpes2, index) = args.tail.head + arrSize <- array.arrayCapabilities.length(arr, Seq.empty) + func <- find_method_recursive(names.mangle("helper")) + + index_1 <- arithmetic.arithmeticCapabilities.add(index, one) + + ans <- impParadigm.imperativeCapabilities.declareVar(names.mangle("result"), intType, Some(zero)) + + ifCond1 <- arithmetic.arithmeticCapabilities.lt(arrSize, index) + ifCond2 <- eqls.equalityCapabilities.areEqual(intType, arrSize, index) + ifCond <- booleans.booleanCapabilities.or(Seq(ifCond1, ifCond2)) + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(ifCond, for{ + ansExpr <- impParadigm.imperativeCapabilities.assignVar(ans, zero) + _<- addBlockDefinitions(Seq(ansExpr)) + } yield(), + Seq.empty, + Some( + for{ + arr_index <- array.arrayCapabilities.get(arr, Seq(index)) + cursor <- impParadigm.imperativeCapabilities.declareVar(names.mangle("cur"), intType, Some(arr_index)) + pick <- impParadigm.imperativeCapabilities.declareVar(names.mangle("pick"), intType, Some(zero)) + + whilecond1 <- arithmetic.arithmeticCapabilities.lt(index, arrSize) + whilecond2 <- eqls.equalityCapabilities.areEqual(intType, cursor, arr_index) + whileCond <- booleans.booleanCapabilities.and(Seq(whilecond1, whilecond2)) + innerwhileStmt <- impParadigm.imperativeCapabilities.whileLoop(whileCond, for{ + pickValue <- arithmetic.arithmeticCapabilities.add(pick, arr_index) + pickExpr <- impParadigm.imperativeCapabilities.assignVar(pick, pickValue) + indexExpr <- impParadigm.imperativeCapabilities.assignVar(index, index_1) + _<-addBlockDefinitions(Seq(pickExpr, indexExpr)) + } yield()) + _<-addBlockDefinitions(Seq(innerwhileStmt)) + + resValue <- apply(func, Seq(arr, index)) + ansExpr <- impParadigm.imperativeCapabilities.assignVar(ans, resValue) + _<-addBlockDefinitions(Seq(ansExpr)) + + cursor_1 <- arithmetic.arithmeticCapabilities.add(cursor, one) + whilecond3 <- eqls.equalityCapabilities.areEqual(intType, arr_index, cursor_1) + whileCond <- booleans.booleanCapabilities.and(Seq(whilecond1, whilecond3)) + innerwhileStmt <- impParadigm.imperativeCapabilities.whileLoop(whileCond, for{ + indexExpr <- impParadigm.imperativeCapabilities.assignVar(index, index_1) + _<-addBlockDefinitions(Seq(indexExpr)) + } yield()) + _<-addBlockDefinitions(Seq(innerwhileStmt)) + + pick_plusAns <- arithmetic.arithmeticCapabilities.add(pick, resValue) + ifcond <- arithmetic.arithmeticCapabilities.lt(ans, pick_plusAns) + innerIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(ifcond, for{ + ansExpr <- impParadigm.imperativeCapabilities.assignVar(ans, pick_plusAns) + _<-addBlockDefinitions(Seq(ansExpr)) + } yield(), + Seq.empty, + ) + + _<-addBlockDefinitions(Seq(innerIfStmt)) + + } yield() + )) + + _<-addBlockDefinitions(Seq(ifStmt)) + } yield(Some(ans)) + } + + /* + public int solution(int[] nums) { + bubbleSort(nums); + return dfs(nums, 0); + } + */ + + def solution(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + _ <- makeSolutionSignature() + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + args <- getArguments() + intType <- toTargetLanguageType(TypeRep.Int) + (names1, tpes1, arr) = args.head + sort_func <- find_method_recursive(names.mangle("Bubble_sort")) + recur_func <- find_method_recursive(names.mangle("helper")) + sorted_arr <- apply(sort_func, Seq(arr)) + ansValue <- apply(recur_func, Seq(sorted_arr, zero)) + + } yield(Some(ansValue)) + } + + + + + + /** Create the HouseRobber class with rob() method. */ + def makeClass(clazzName: String): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("Bubble_sort"), Bubble_sort()) + _ <- addMethod(names.mangle("helper"), helper()) + _<- addMethod(names.mangle("solution"), solution()) + + } yield None + } + addClassToProject(makeClass, names.mangle(clazzName)) + } + + /** Main class to test rob() method */ + def makeMainClass(clazzName: String): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("main"), staticMainImplementation()) + } yield () + } + addClassToProject(makeClass, names.mangle(clazzName)) + } + + /** Example main implementation */ + def staticMainImplementation(): Generator[MethodBodyContext, Option[Expression]] = { + import impParadigm.imperativeCapabilities._ + import ooParadigm.methodBodyCapabilities._ + import paradigm.methodBodyCapabilities._ + + for { + _ <- setStatic() + unitType <- toTargetLanguageType(TypeRep.Unit) + _ <- setReturnType(unitType) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + nums <- declareVar(names.mangle("nums"), arrayType, None) // in real impl: initialize + // Example call: HouseRobber.rob(nums) + // Example print result + } yield None + } + + /** Entry point */ + def implement(): Generator[ProjectContext, Unit] = { + for { + _ <- makeClass("DeleteAndEarn") + _ <- makeMainClass("Main") + } yield () + } +} + +object DeleteAndEarnObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = DeleteAndEarnObjectOrientedProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + boolsIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : DeleteAndEarnObjectOrientedProvider.WithParadigm[base.type] = + new DeleteAndEarnObjectOrientedProvider { + override val paradigm: base.type = base + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = boolsIn + } +} + diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursionJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/JumpTo/JumpToMainJava.scala similarity index 57% rename from helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursionJava.scala rename to dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/JumpTo/JumpToMainJava.scala index 096dbdf9..fca73336 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursionJava.scala +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/JumpTo/JumpToMainJava.scala @@ -1,29 +1,26 @@ -package org.combinators.fibonacci +package org.combinators.archive.cogen.topDown.oneSequence.JumpTo /** - * Not yet completed. + * One of the earliest implementations to solve JumpTo but NO TEST CASES. * - * This effort will eventually yield the ability to generate a recursive function simply by - * identifying (a) the base cases; and (b) the recursive call structure. + * val targetDirectory = Paths.get("target", "JumpTo") */ - import cats.effect.{ExitCode, IO, IOApp} import com.github.javaparser.ast.PackageDeclaration import org.apache.commons.io.FileUtils import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} -import org.combinators.cogen.FileWithPathPersistable._ +import FileWithPathPersistable._ import org.combinators.ep.language.java.paradigm.ObjectOriented import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} import java.nio.file.{Path, Paths} /** - * Takes language-independent specification of Fibonacci with Lucas and generates Java code + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. */ -class GenericRecursionMainJava { - val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("fibonacci")))) - - val fibonacciApproach = GenericRecursionProvider.imperative[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.ooParadigm, generator.imperativeInMethod, generator.intsInMethod, generator.assertionsInMethod, generator.equalityInMethod, generator.booleansInMethod, generator.realDoublesInMethod) +class JumpToMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("JumpTo")))) + val jtApproach = JumpToObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.equalityInMethod, generator.booleansInMethod) val persistable = FileWithPathPersistable[FileWithPath] @@ -32,16 +29,20 @@ class GenericRecursionMainJava { val files = () => generator.paradigm.runGenerator { for { + _ <- generator.doublesInMethod.enable() _ <- generator.intsInMethod.enable() - _ <- generator.booleansInMethod.enable() _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() _ <- generator.equalityInMethod.enable() _ <- generator.assertionsInMethod.enable() - _ <- fibonacciApproach.make_project() + + _ <- jtApproach.implement() } yield () } - IO { + IO { print("Computing Files...") val computed = files() println("[OK]") @@ -51,7 +52,7 @@ class GenericRecursionMainJava { println("[OK]") } print("Persisting Files...") - computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) println("[OK]") } } @@ -63,16 +64,15 @@ class GenericRecursionMainJava { } } -// doesn't work since CAST does not work on (Integer) Math.floor(..) -object GenericRecursionJavaDirectToDiskMain extends IOApp { - val targetDirectory = Paths.get("target", "fib", "java") - print(targetDirectory) +object JumpToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "JumpTo") + def run(args: List[String]): IO[ExitCode] = { for { _ <- IO { print("Initializing Generator...") } - main <- IO { new GenericRecursionMainJava() } + main <- IO { new JumpToMainJava() } _ <- IO { println("[OK]") } result <- main.runDirectToDisc(targetDirectory) } yield result } -} +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/JumpTo/JumpToObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/JumpTo/JumpToObjectOrientedProvider.scala new file mode 100644 index 00000000..c141cede --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/JumpTo/JumpToObjectOrientedProvider.scala @@ -0,0 +1,333 @@ +package org.combinators.archive.cogen.topDown.oneSequence.JumpTo + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen._ +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.Booleans.WithBase +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} + +trait JumpToObjectOrientedProvider { + val paradigm: AnyParadigm + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + res <- ooParadigm.methodBodyCapabilities.getMember(self, name) + } yield res + } + + def makeHelperSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for{ + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _<- setParameters( + Seq((names.mangle("arr"), arrayType)) + ) + _<- setReturnType(intType) + } yield() + } + + def makeMinJumpRecSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for{ + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _<- setParameters( + Seq((names.mangle("arr"), arrayType), + (names.mangle("index"), intType)) + ) + _<- setReturnType(intType) + } yield() + } + + def makeminJumpsSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for{ + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _<- setParameters( + Seq((names.mangle("arr"), arrayType)) + ) + _<- setReturnType(intType) + } yield() + } + + /* + int retrieveMax(int[] arr) { + int max = 0; + for (int i = 0; i < arr.length; i++) { + if (arr[i] > max) { + max = arr[i]; + } + } + return max+1; + } + */ + + def retireve_max(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + _<- makeHelperSignature() + args <- getArguments() + (namen,tpen,arr) = args.head + intType <- toTargetLanguageType(TypeRep.Int) + size <- array.arrayCapabilities.length(arr, Seq.empty) + + ansExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("ans"), intType, Some(zero)) + iVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("i"), intType, Some(zero)) + arrSizeExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("size"), intType, Some(size)) + whileCond <- arithmetic.arithmeticCapabilities.lt(iVar,arrSizeExpr) + + for_stmt <- impParadigm.imperativeCapabilities.whileLoop(whileCond, for{ + arr_index <- array.arrayCapabilities.get(arr, Seq(iVar)) + if_cond <- arithmetic.arithmeticCapabilities.lt(ansExpr, arr_index) + innerIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(if_cond, for{ + assignStmt <- impParadigm.imperativeCapabilities.assignVar(ansExpr, arr_index) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield(), + Seq.empty) + _ <- addBlockDefinitions(Seq(innerIfStmt)) + + iVar_one <- arithmetic.arithmeticCapabilities.add(iVar, one) + assignStmt <- impParadigm.imperativeCapabilities.assignVar(iVar, iVar_one) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield()) + + _ <- addBlockDefinitions(Seq(for_stmt)) + + ans_1 <- arithmetic.arithmeticCapabilities.add(ansExpr, one) + assignStmt <- impParadigm.imperativeCapabilities.assignVar(ansExpr, ans_1) + _<- addBlockDefinitions(Seq(assignStmt)) + } yield(Some(ansExpr)) + } + + /* + int minJumpsRecur(int i, int[] arr) { + int ans = 0; + if (i < arr.length - 1){ + ans = retrieveMax(arr); + for (int j = i + 1; j <= i + arr[i]; j++) { + int val = minJumpsRecur(j, arr); + if (val != retrieveMax(arr) && 1+val < ans) { + ans = val+1; + } + } + } + return ans; + } + */ + def minJumpRec(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + _ <- makeMinJumpRecSignature() + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + args <- getArguments() + intType <- toTargetLanguageType(TypeRep.Int) + (names1, tpes1, arr) = args.head + (names2, tpes2, index) = args.tail.head + retrieve_func <- find_method_recursive(names.mangle("retrieveMax")) + recur_func <- find_method_recursive(names.mangle("minJumpsRecur")) + maxValue <- apply(retrieve_func, Seq(arr)) + + ansExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("ans"), intType, Some(zero)) + arr_size <- array.arrayCapabilities.length(arr, Seq.empty) + arrLength_1 <- arithmetic.arithmeticCapabilities.sub(arr_size, one) + + if_cond <- arithmetic.arithmeticCapabilities.lt(index, arrLength_1) + if_Stmt <- impParadigm.imperativeCapabilities.ifThenElse(if_cond, for{ + assignStmt <- impParadigm.imperativeCapabilities.assignVar(ansExpr, maxValue) + _<- addBlockDefinitions(Seq(assignStmt)) + + index_one <- arithmetic.arithmeticCapabilities.add(index, one) + mark <- impParadigm.imperativeCapabilities.declareVar(names.mangle("i"), intType, Some(index_one)) + arr_index <- array.arrayCapabilities.get(arr, Seq(index)) + index_arr_index <- arithmetic.arithmeticCapabilities.add(index, arr_index) + for_cond1 <- arithmetic.arithmeticCapabilities.lt(mark, index_arr_index) + for_cond2 <- eqls.equalityCapabilities.areEqual(intType, mark, index_arr_index) + for_cond <- booleans.booleanCapabilities.or(Seq(for_cond1, for_cond2)) + + forStmt <- impParadigm.imperativeCapabilities.whileLoop(for_cond, for{ + arr_mark <- apply(recur_func, Seq(arr, mark)) + valExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("var"), intType, Some(arr_mark)) + innerIfNotCond <- eqls.equalityCapabilities.areEqual(intType, valExpr, maxValue) + innerIfCond1 <- booleans.booleanCapabilities.not(innerIfNotCond) + + val_1 <- arithmetic.arithmeticCapabilities.add(valExpr, one) + innerIfCond2 <- arithmetic.arithmeticCapabilities.lt(val_1, ansExpr) + innerIfCond <- booleans.booleanCapabilities.and(Seq(innerIfCond1, innerIfCond2)) + innerIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(innerIfCond, for{ + + assignStmt <- impParadigm.imperativeCapabilities.assignVar(ansExpr, val_1) + _<-addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty + ) + + _<-addBlockDefinitions(Seq(innerIfStmt)) + + mark_1 <- arithmetic.arithmeticCapabilities.add(mark, one) + assignStmt <- impParadigm.imperativeCapabilities.assignVar(mark, mark_1) + _<- addBlockDefinitions(Seq(assignStmt)) + } yield() + ) + + _<- addBlockDefinitions(Seq(forStmt)) + + }yield (), + Seq.empty + ) + + _<- addBlockDefinitions(Seq(if_Stmt)) + + + } yield(Some(ansExpr)) + } + + /* + int minJumps(int[] arr) { + + int answer = minJumpsRecur(0, arr); + + if (answer == retrieveMax(arr)) + return -1; + + return answer; + } + */ + + def minJumps(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + _ <- makeminJumpsSignature() + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + neg_one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -1) + args <- getArguments() + intType <- toTargetLanguageType(TypeRep.Int) + (names1, tpes1, arr) = args.head + retrieve_func <- find_method_recursive(names.mangle("retrieveMax")) + recur_func <- find_method_recursive(names.mangle("minJumpsRecur")) + maxValue <- apply(retrieve_func, Seq(arr)) + + ansValue <- apply(recur_func, Seq(arr, zero)) + ansExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("ans"), intType, Some(ansValue)) + + if_cond <- eqls.equalityCapabilities.areEqual(intType, ansExpr, maxValue) + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(if_cond, for{ + assignStmt <- impParadigm.imperativeCapabilities.assignVar(ansExpr, neg_one) + _<- addBlockDefinitions(Seq(assignStmt)) + }yield (), + Seq.empty) + + _<- addBlockDefinitions(Seq(ifStmt)) + } yield(Some(ansExpr)) + } + + /** Create the HouseRobber class with rob() method. */ + def makeClass(clazzName: String): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("retrieveMax"), retireve_max()) + _ <- addMethod(names.mangle("minJumpsRecur"), minJumpRec()) + _<- addMethod(names.mangle("minJumps"), minJumps()) + + } yield None + } + addClassToProject(makeClass, names.mangle(clazzName)) + } + + /** Main class to test rob() method */ + def makeMainClass(clazzName: String): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("main"), staticMainImplementation()) + } yield () + } + addClassToProject(makeClass, names.mangle(clazzName)) + } + + /** Example main implementation */ + def staticMainImplementation(): Generator[MethodBodyContext, Option[Expression]] = { + import impParadigm.imperativeCapabilities._ + import ooParadigm.methodBodyCapabilities._ + import paradigm.methodBodyCapabilities._ + + for { + _ <- setStatic() + unitType <- toTargetLanguageType(TypeRep.Unit) + _ <- setReturnType(unitType) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + nums <- declareVar(names.mangle("nums"), arrayType, None) // in real impl: initialize + // Example call: HouseRobber.rob(nums) + // Example print result + } yield None + } + + /** Entry point */ + def implement(): Generator[ProjectContext, Unit] = { + for { + _ <- makeClass("JumpTo") + _ <- makeMainClass("Main") + } yield () + } +} + +object JumpToObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = JumpToObjectOrientedProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + boolsIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : JumpToObjectOrientedProvider.WithParadigm[base.type] = + new JumpToObjectOrientedProvider { + override val paradigm: base.type = base + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = boolsIn + } +} + diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/houseRobber/HouseRobberMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/houseRobber/HouseRobberMainJava.scala new file mode 100644 index 00000000..4287776e --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/houseRobber/HouseRobberMainJava.scala @@ -0,0 +1,75 @@ +package org.combinators.archive.cogen.topDown.oneSequence.houseRobber + +/** + * One of the earliest implementations to solve HouseRobber but NO TEST CASES. + * + * val targetDirectory = Paths.get("target", "houserobber") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} + +import java.nio.file.{Path, Paths} + +class HouseRobberMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("robber")))) + val hrApproach = HouseRobberObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + + _ <- hrApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object HouseRobberDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "houserobber") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new HouseRobberMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/houseRobber/HouseRobberObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/houseRobber/HouseRobberObjectOrientedProvider.scala new file mode 100644 index 00000000..cd389239 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/houseRobber/HouseRobberObjectOrientedProvider.scala @@ -0,0 +1,382 @@ +package org.combinators.archive.cogen.topDown.oneSequence.houseRobber + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen._ +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.Booleans.WithBase +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality} +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} + +/** + * One of the earliest implementations to solve HouseRobber but NO TEST CASES. + */ +trait HouseRobberObjectOrientedProvider { + val paradigm: AnyParadigm + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + /* + int rob(int[] hval, int n){ + int result; + if(n <= 0){ + result = 0; + } else if(n == 1){ + result = hval[0]; + } else { + int pick = hval[n-1] + rob(hval, n-2); + int notpick = rob(hval, n-1); + if(pick < notpick){ + result = notpick; + } else { + result = pick; + } + } + return result + } + */ + + def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + res <- ooParadigm.methodBodyCapabilities.getMember(self, name) + } yield res + } + + /** Method signature: int rob(int[] nums) */ + def makeRobSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + for { + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _ <- setParameters(Seq((names.mangle("nums"), arrayType))) + _ <- setReturnType(intType) + } yield () + } + + // public int some(int[] hval, int b) { + // + def makeSomeSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + for { + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _ <- setParameters(Seq( + (names.mangle("hval"), arrayType), + (names.mangle("b"), intType))) + _ <- setReturnType(intType) + } yield () + } + + def makeSolutionSignature(): Generator[MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + for{ + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setParameters(Seq((names.mangle("hval"), arrayType))) + _ <- setReturnType(intType) + } yield() + } + + def make_solution(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for{ + _ <- makeSolutionSignature() + args <- getArguments() + intType <- toTargetLanguageType(TypeRep.Int) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + (namen,tpen,nums) = args.head + func <- find_method_recursive(names.mangle("rob")) + size <- array.arrayCapabilities.length(nums, Seq.empty) + + resultExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("result"), intType, Some(zero)) + lengthExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("n"), intType, Some(size)) + // assignStmt <- impParadigm.imperativeCapabilities.assignVar(lengthExpr, size) + // _ <- addBlockDefinitions(Seq(assignStmt)) + + resultValue <- apply(func, Seq(nums, lengthExpr)) + assignStmt <- impParadigm.imperativeCapabilities.assignVar(resultExpr, resultValue) + _ <- addBlockDefinitions(Seq(assignStmt)) + + + + } yield(Some(resultExpr)) + } + + def someMethodImplementation(): Generator[MethodBodyContext, Option[Expression]] = { + for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + _ <- makeSomeSignature() + } yield Some(zero) + } + + /** Method implementation: top-down DP with memoization (pseudocode). */ + def robMethodImplementation(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + for { + _ <- makeRobSignature() + // Pseudocode for body: + // int n = nums.length; + // int[] memo = new int[n]; + // Arrays.fill(memo, -1); + // return helper(0, nums, memo); + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + intType <- toTargetLanguageType(TypeRep.Int) + + iVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("i"), intType, Some(one)) // won't work + + // Integer i = 1; + // if (i <= 0) { + // i = 0; + // + guard1 <- arithmetic.arithmeticCapabilities.lt(iVar, zero) + guard2 <- eqls.equalityCapabilities.areEqual(intType, iVar, zero) + combined_guard <- booleans.booleanCapabilities.or(Seq(guard1, guard2)) + innerIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(combined_guard, for { + assignStmt <- impParadigm.imperativeCapabilities.assignVar(iVar, zero) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty + ) + _ <- addBlockDefinitions(Seq(innerIfStmt)) + + // In practice: declare vars, loop, call helper (another method). + } yield Some(iVar) + } + + def make_maxLoot_compute_signature(): Generator[paradigm.MethodBodyContext, Unit] ={ + import paradigm.methodBodyCapabilities._ + + for{ + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _ <- setParameters(Seq( + (names.mangle("hval"), arrayType), + (names.mangle("n"), intType))) + _ <- setReturnType(intType) + } yield () + } + + /** + + // Base case: no more houses + int return_value; + if (i < nums.length) { + + if (dp[i] != -1) { + return_value = dp[i]; + } else { + + int robCurrent = nums[i] + helper(nums, i + 2, dp); + + int skipCurrent = helper(nums, i + 1, dp); + + dp[i] = Math.max(robCurrent, skipCurrent); + + return_value = dp[i]; + } + } else { + return_value = 0; + } + + return return_value; + + * @return + */ + + def make_maxloot_compute(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + for { + _ <- make_maxLoot_compute_signature() + arg <- getArguments() + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + two <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + intType <- toTargetLanguageType(TypeRep.Int) + + (names1, tpes1, hval) = arg.head + (names2, tpes2, n) = arg.tail.head + + func <- find_method_recursive(names.mangle("rob")) + + guard_nLt0 <- arithmetic.arithmeticCapabilities.lt(n, zero) + guard_nEQ0 <- eqls.equalityCapabilities.areEqual(intType, n, zero) + combined_guard <- booleans.booleanCapabilities.or(Seq(guard_nLt0, guard_nEQ0)) + guard2 <- eqls.equalityCapabilities.areEqual(intType, n, one) + size <- array.arrayCapabilities.length(hval, Seq.empty) + + n_1 <- arithmetic.arithmeticCapabilities.sub(n, one) + n_2 <- arithmetic.arithmeticCapabilities.sub(n, two) + houseHoldValue <- array.arrayCapabilities.get(hval, Seq(n_1)) + + notpickExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("notpick"), intType, Some(zero)) + notpick2Expr <- apply(func, Seq(hval, n_1)) + notPickStmt <- impParadigm.imperativeCapabilities.assignVar(notpickExpr, notpick2Expr) + _ <- addBlockDefinitions(Seq(notPickStmt)) + + pickExpr <- impParadigm.imperativeCapabilities.declareVar(names.mangle("pick"), intType, Some(zero)) + pick2Expr <- apply(func, Seq(hval, n_2)) + pickResult <- arithmetic.arithmeticCapabilities.add(houseHoldValue, pick2Expr) + pickStmt <- impParadigm.imperativeCapabilities.assignVar(pickExpr, pickResult) + _ <- addBlockDefinitions(Seq(pickStmt)) + + hval_0_ <- array.arrayCapabilities.get(hval, Seq(zero)) + + // set hval[0] = 1 + indexedLocation <- array.arrayCapabilities.get(hval, Seq(zero)) + setIL <- impParadigm.imperativeCapabilities.assignVar(indexedLocation, one) + + returnresult <- impParadigm.imperativeCapabilities.declareVar(names.mangle("result"), intType) + returnStmt <- impParadigm.imperativeCapabilities.assignVar(returnresult, zero) + + _<- addBlockDefinitions(Seq(returnStmt)) + + guard_Inner <- arithmetic.arithmeticCapabilities.lt(pickExpr, notpickExpr) + + innerIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(combined_guard, for { + assignStmt <- impParadigm.imperativeCapabilities.assignVar(returnresult, zero) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq((guard2, for{ + assignStmt <- impParadigm.imperativeCapabilities.assignVar(returnresult, hval_0_) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield(), + + ) + ), + Some( + for{ + inner2IfStmt <- impParadigm.imperativeCapabilities.ifThenElse(guard_Inner, for{ + assignStmt <- impParadigm.imperativeCapabilities.assignVar(returnresult, notpickExpr) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield(), + Seq.empty, + Some( + for{ + assignStmt2 <- impParadigm.imperativeCapabilities.assignVar(returnresult, pickExpr) + _ <- addBlockDefinitions(Seq(assignStmt2)) + } yield() + )) + + _ <- addBlockDefinitions(Seq(inner2IfStmt)) + + } yield() + ) + ) + _ <- addBlockDefinitions(Seq(innerIfStmt)) + + innerIfStmt2 <- impParadigm.imperativeCapabilities.ifThenElse(guard2, for { + assignStmt <- impParadigm.imperativeCapabilities.assignVar(returnresult, hval_0_) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty + ) + + } yield Some(returnresult) + } + + /** + * + + if(pick < notpick){ + result = notpick; + } else if(notpick < pick){ + result = pick; + } + */ + /** Create the HouseRobber class with rob() method. */ + def makeClass(clazzName: String): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("rob"), make_maxloot_compute()) + _ <- addMethod(names.mangle("solution"), make_solution()) + } yield None + } + addClassToProject(makeClass, names.mangle(clazzName)) + } + + /** Main class to test rob() method */ + def makeMainClass(clazzName: String): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("main"), staticMainImplementation()) + } yield () + } + addClassToProject(makeClass, names.mangle(clazzName)) + } + + /** Example main implementation */ + def staticMainImplementation(): Generator[MethodBodyContext, Option[Expression]] = { + import impParadigm.imperativeCapabilities._ + import ooParadigm.methodBodyCapabilities._ + import paradigm.methodBodyCapabilities._ + + for { + _ <- setStatic() + unitType <- toTargetLanguageType(TypeRep.Unit) + _ <- setReturnType(unitType) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + nums <- declareVar(names.mangle("nums"), arrayType, None) // in real impl: initialize + // Example call: HouseRobber.rob(nums) + // Example print result + } yield None + } + + /** Entry point */ + def implement(): Generator[ProjectContext, Unit] = { + for { + _ <- makeClass("HouseRobber") + _ <- makeMainClass("Main") + } yield () + } +} + +object HouseRobberObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = HouseRobberObjectOrientedProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + boolsIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : HouseRobberObjectOrientedProvider.WithParadigm[base.type] = + new HouseRobberObjectOrientedProvider { + override val paradigm: base.type = base + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = boolsIn + } +} + diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/tribonacci/TribonacciMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/tribonacci/TribonacciMainJava.scala new file mode 100644 index 00000000..b46d092a --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/tribonacci/TribonacciMainJava.scala @@ -0,0 +1,88 @@ +package org.combinators.archive.cogen.topDown.oneSequence.tribonacci + +/** + * One of the earliest implementations to generate a successful top-down implementation of Tribonacci with test cases. + * + * This showed the potential of writing pure CoGen code to handle all generators, though one can see how quickly this + * becomes inefficient: it is hard to imagine reusable blocks of code that could be reused across different DP solutions. + * + * val targetDirectory = Paths.get("target", "topDown", "oneSequence", "tribonacci") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} + +import java.nio.file.{Path, Paths} + +/** + * One of the earliest implementations to generate a successful top-down Tribonacci WITH test cases. + * + * This showed the potential of writing pure CoGen code to handle all generators, though one can see how quickly this + * becomes inefficient: it is hard to imagine reusable blocks of code that could be reused across different DP solutions. + */ +class TribonacciMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + + val dpApproach = TribonacciTopDownProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object TribonacciDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "tribonacci") + + def run(args: List[String]): IO[ExitCode] = { + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new TribonacciMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/tribonacci/TribonacciTopDownProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/tribonacci/TribonacciTopDownProvider.scala new file mode 100644 index 00000000..6a0f4ad8 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/oneSequence/tribonacci/TribonacciTopDownProvider.scala @@ -0,0 +1,250 @@ +package org.combinators.archive.cogen.topDown.oneSequence.tribonacci + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.* +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.TestExample +import org.combinators.dp.original.Utility +import org.combinators.models.{LiteralInt, UnitExpression} + +/** + * One of the earliest implementations to generate a successful top-down Tribonacci with tests. + * + * Still uses the no-argument constructor while passing the argument into compute() method. + */ +trait TribonacciTopDownProvider extends Utility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message: String = "message" + lazy val main: String = "main" + lazy val testName = names.mangle("TestSuite") + lazy val dpName = names.mangle("dp") + lazy val memoName = names.mangle("memo") + + lazy val rName = names.mangle("r") + lazy val cName = names.mangle("c") + + var memo: Boolean = false + + lazy val resultVarName = names.mangle("result") + + def getter(attr: String): String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setParameters(Seq((names.mangle("n"), intType))) + _ <- setReturnType(intType) + + } yield () + } + + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + _ <- make_compute_method_signature() + args <- getArguments() + + self <- ooParadigm.methodBodyCapabilities.selfReference() + func <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle("compute")) + + (name, tpe, n) = args.head + + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + two <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + three <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 3) + + neq0 <- arithmetic.arithmeticCapabilities.le(n, zero) + neq2 <- arithmetic.arithmeticCapabilities.le(n, two) + + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse( + neq0, + for { + returnStmt <- impParadigm.imperativeCapabilities.returnStmt(zero) + _ <- addBlockDefinitions(Seq(returnStmt)) + } yield (), + Seq( + (neq2, + for { + returnStmt <- impParadigm.imperativeCapabilities.returnStmt(one) + _ <- addBlockDefinitions(Seq(returnStmt)) + } yield ()), + ), + Some( + for { + n_1 <- arithmetic.arithmeticCapabilities.sub(n, one) + fn_1 <- apply(func, Seq(n_1)) + n_2 <- arithmetic.arithmeticCapabilities.sub(n, two) + fn_2 <- apply(func, Seq(n_2)) + n_3 <- arithmetic.arithmeticCapabilities.sub(n, three) + fn_3 <- apply(func, Seq(n_3)) + + out <- arithmetic.arithmeticCapabilities.add(fn_1, fn_2) + out <- arithmetic.arithmeticCapabilities.add(out, fn_3) + returnStmt <- impParadigm.imperativeCapabilities.returnStmt(out) + _ <- addBlockDefinitions(Seq(returnStmt)) + } yield () + ) + ) + + _ <- addBlockDefinitions(Seq(ifStmt)) + } yield None + } + + def makeSimpleDP(): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("compute"), make_compute_method()) + } yield None + } + + addClassToProject(makeClass, names.mangle("Tribonacci")) + } + + // Specific examples hard coded for Int input and Int output + def makeTestCases(): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities.* + import paradigm.methodBodyCapabilities.* + import syntax._ + + // 0, 1, 1, 2, 4, 7, 13, 24, ... + // + // 0 1 2 3 4 5 6 7 + val tests = Seq( + new TestExample("trib0", LiteralInt(0), LiteralInt(0), new UnitExpression), // for now, leave solution as None + new TestExample("trib1", LiteralInt(1), LiteralInt(1), new UnitExpression), + new TestExample("trib2", LiteralInt(2), LiteralInt(1), new UnitExpression), + new TestExample("trib7", LiteralInt(3), LiteralInt(2), new UnitExpression), + new TestExample("trib20", LiteralInt(4), LiteralInt(4), new UnitExpression), + new TestExample("trib40", LiteralInt(5), LiteralInt(7), new UnitExpression) + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralInt => lt.literal + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit: LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle("Tribonacci")) + n_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, input_value) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq.empty) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq(n_value)) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + def makeTestCase(clazzName:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestCases(), names.mangle(clazzName)) + } yield () + } + + def implement(): Generator[ProjectContext, Unit] = { + // + // var isTopDown = false + // + // option match { + // case td: TopDown => + // memo = td.memo + // isTopDown = true + // case _: BottomUp => + // isTopDown = false + // } + // + // for { + // _ <- if (isTopDown) { + // make_top_down(model) + // } else { + // make_bottom_up(model) + // } + // } yield () + + for { + _ <- makeSimpleDP() + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(testName, makeTestCase("DP")) + ) + } yield None + } +} + +object TribonacciTopDownProvider { + type WithParadigm[P <: AnyParadigm] = TribonacciTopDownProvider {val paradigm: P} + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): TribonacciTopDownProvider.WithParadigm[base.type] = + new TribonacciTopDownProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/pascal/PascalMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/pascal/PascalMainJava.scala new file mode 100644 index 00000000..fc123c5c --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/pascal/PascalMainJava.scala @@ -0,0 +1,81 @@ +package org.combinators.archive.cogen.topDown.pascal + +/** + * One of the earliest implementations to generate a successful top-down implementation of Pascal's Triangle WITH test cases. + * + * val targetDirectory = Paths.get("target", "pascal") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Unboxed, Syntax} + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class PascalMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) + + val dpApproach = PascalObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.booleansInMethod) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object PascalDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "pascal") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new PascalMainJava() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/pascal/PascalObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/pascal/PascalObjectOrientedProvider.scala new file mode 100644 index 00000000..faf87792 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/cogen/topDown/pascal/PascalObjectOrientedProvider.scala @@ -0,0 +1,241 @@ +package org.combinators.archive.cogen.topDown.pascal + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, FindClass, ObjectOriented} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep, Understands} +import org.combinators.dp.original.Utility +import org.combinators.models.{LiteralInt, UnitExpression} +import org.combinators.archive.unenhancedModels.models.LiteralPair + +/** + * One of the earliest implementations to generate a successful top-down implementation of Pascal's Triangle WITH test cases. + */ +trait PascalObjectOrientedProvider extends Utility { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext,paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext,paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + res <- ooParadigm.methodBodyCapabilities.getMember(self, name) + } yield res + } + + /** Define standard test name. */ + def testCaseName: paradigm.syntax.Name = { + names.mangle("Test") + } + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val message:String = "message" + lazy val main:String = "main" + lazy val testName = names.mangle("TestSuite") + lazy val compute = names.mangle("compute") + + def getter(attr:String) : String = { + "get" + attr.capitalize + } + + def make_compute_method_signature(): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + + for { + intType <- toTargetLanguageType(TypeRep.Int) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + _ <- setParameters(Seq((names.mangle("r"), intType),(names.mangle("c"), intType))) + _ <- setReturnType(intType) + + } yield () + } + + def make_compute_method(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + _ <- make_compute_method_signature() + args <- getArguments() + + func <- find_method_recursive(names.mangle("compute")) + + intType <- toTargetLanguageType(TypeRep.Int) + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + (namer,tper,r) = args.head + (namec,tpec,c) = args.tail.head + + + /* + //Code for HashMap (doesn't work) + mapClass <- findClass(names.mangle("java"), names.mangle("util"), names.mangle("HashMap")) + _ <- resolveAndAddImport(mapClass) + mapInst <- instantiateObject(mapClass, Seq.empty, None) + mapVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("mymap"), mapClass, Some(mapInst)) + */ + + lec0 <- arithmetic.arithmeticCapabilities.le(c, zero) + + ler0 <- arithmetic.arithmeticCapabilities.le(r, zero) + + resultName <- freshName(names.mangle("result")) + resultVar <- impParadigm.imperativeCapabilities.declareVar(resultName, intType, Some(zero)) + + r_1 <- arithmetic.arithmeticCapabilities.sub(r, one) + c_1 <- arithmetic.arithmeticCapabilities.sub(c, one) + app1 <- apply(func, Seq(r_1,c)) + app2 <- apply(func, Seq(r_1,c_1)) + recSum <- arithmetic.arithmeticCapabilities.add(app1,app2) + + ifStmt <- impParadigm.imperativeCapabilities.ifThenElse(lec0, for { + + assignStmt1 <- impParadigm.imperativeCapabilities.assignVar(resultVar, one) + _ <- addBlockDefinitions(Seq(assignStmt1)) + } yield (), + + Seq((ler0, + for { + assignStmt2 <- impParadigm.imperativeCapabilities.assignVar(resultVar, zero) + _ <- addBlockDefinitions(Seq(assignStmt2)) + } yield () )), + + Some( + for { + assignStmt3<- impParadigm.imperativeCapabilities.assignVar(resultVar, recSum) + _ <- addBlockDefinitions(Seq(assignStmt3)) + } yield ()) + ) + _ <- addBlockDefinitions(Seq(ifStmt)) + + } yield Some(resultVar) + } + /** + public int pascal(int r, int c) { + if(c==0) + return 1; + if(r==0) + return 0; + + + return pascal(r-1,c-1)+pascal(r-1,c); + } + */ + def makeSimpleDP(): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- addMethod(names.mangle("compute"), make_compute_method()) + } yield None + } + + addClassToProject(makeClass, names.mangle("Pascal")) + } + + def makeTestCase(): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + val tests = Seq( + new TestExample("pasc11", LiteralPair(1,1), LiteralInt(1), new UnitExpression), + new TestExample("pasc32", LiteralPair(3,2), LiteralInt(3), new UnitExpression), + new TestExample("pasc63", LiteralPair(6,3), LiteralInt(20), new UnitExpression), + new TestExample("pasc2013", LiteralPair(20,13), LiteralInt(77520), new UnitExpression), + ) + + for { + assert_statements <- forEach(tests) { example => + + val pair = example.inputType match { + case lp:LiteralPair => (lp.val1, lp.val2) + case _ => ??? + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + pascType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle("Pascal")) + r_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, pair._1) + c_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, pair._2) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(pascType, Seq.empty) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, compute) + + intType <- toTargetLanguageType(TypeRep.Int) + pascrc_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + pascrc_actual <- apply(computeMethod, Seq(r_value,c_value)) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, pascrc_actual, pascrc_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + def makeTestCase(clazzName:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestCase(), names.mangle(clazzName)) + } yield () + } + + def implement(): Generator[ProjectContext, Unit] = { + + for { + _ <- makeSimpleDP() + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(testName, makeTestCase("DP")) + ) + } yield () + } +} + +object PascalObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = PascalObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + oo: ObjectOriented.WithBase[base.type], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + : PascalObjectOrientedProvider.WithParadigm[base.type] = + new PascalObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/README.md b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/README.md new file mode 100644 index 00000000..1bd4eff7 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/README.md @@ -0,0 +1,58 @@ +We designed a Model class that was meant to provide all information for a DP problem. + +```class Model(val problem:String, + val bounds: List[ArgExpression], + val cases: List[(Option[Expression], Expression)], + val retrieveLabel: String = "take sub-solution") +``` + +It is best to explain this with a simple model that captures the Fibonacci domain + +# Fibonacci + +``` + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + val bound = List(ArgExpression(0, "n", IntegerType(), "i")) + + val i: IteratorExpression = IteratorExpression(0, "i") + + new Model("Fibonacci", + bound, + cases = List( + (Some(i == zero), zero), + (Some(i == one), one), + (None, SubproblemExpression(Seq(i - one)) + SubproblemExpression(Seq(i - two)) ) + ) + ) + } +``` + +The `bounds` represents the arguments to the problem -- in this case, Fibonacci(n). `n` is an argument of type integer, and it is the 0th argument +for this problem. The variable "i" is to be used with iterating over subproblems in `n`. + +The `cases` represents an ordered list of pairs, where each pair has an optional guard that, if true, yields the corresponding expression. + +Thus `Fibonacci(0) = 0` and `Fibonacci(1) = 1`. The interesting case is the recursive case, namely that `Fibonacci(i)` is computed by adding together +the resulting subexpression `Fibonacci(i-1)` and `Fibonacci(i-2)`. + +# Solutions with Model + +* DecodeWays +* Fibonacci +* JumpTo +* UniquePaths +* CoinChange +* KnapSack +* MaxSubArray +* ThreeStrings LongestCommonSubsequence +* DistinctSubsequences +* LongestCommonSubsequence +* MinimumEditDistance +* NeedlemanWunschSequenceAlignment +* UncrossedLines + +In theory, each of these should support both a bottom-up generation and a top-down generation, using the `BottomUpStrategy` and `TopDownStrategy` found +in the `dp.original.BottomUpStrategy` and `dp.original.TopDownStrategy` traits. \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/NWSA/NWSAMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/NWSA/NWSAMainJava.scala new file mode 100644 index 00000000..0791b832 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/NWSA/NWSAMainJava.scala @@ -0,0 +1,96 @@ +package org.combinators.archive.unenhancedModels.boilerplate.NWSA + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.twoSequences.NeedlemanWunschSequenceAlignmentModel +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class NWSAMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = NWSAProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def filesToGenerate(model: Model, option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(model, option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object NWSADirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "archive", "nwsa") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val UL = new NeedlemanWunschSequenceAlignmentModel().instantiate() + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new NWSAMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, UL, topDown) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/NWSA/NWSAProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/NWSA/NWSAProvider.scala new file mode 100644 index 00000000..3178000c --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/NWSA/NWSAProvider.scala @@ -0,0 +1,121 @@ +package org.combinators.archive.unenhancedModels.boilerplate.NWSA + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, LiteralString} +import org.combinators.archive.unenhancedModels.models.LiteralStringPair + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait NWSAProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTests(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("fib0", LiteralStringPair("ACTG", "CGATC"), LiteralInt(2), LiteralString("AC")) // for now, leave solution as None + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralStringPair => (lt.string1, lt.string2) + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + s1_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._1) + s2_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._2) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(s1_value, s2_value)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTests(implementation), names.mangle("DP")) + } yield () + } +} + +object NWSAProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): NWSAProvider.WithParadigm[base.type] = + new NWSAProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/coinChange/CoinChangeMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/coinChange/CoinChangeMainJava.scala new file mode 100644 index 00000000..67f61ab8 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/coinChange/CoinChangeMainJava.scala @@ -0,0 +1,99 @@ +package org.combinators.archive.unenhancedModels.boilerplate.coinChange + +/** + * Partially working implementation of CoinChangeProvider. + * + * 1. Only generates a single test case since the amount cannot be part of test case + * 2. Generates code that must have "fix_topdown.py" applied to it, to ensure code has import java.util.* + * 3. Even then, memo is not generated as a field. + * + * Even so, a good start. + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.knapsack.{CoinChangeModel, KnapsackModel} +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class CoinChangeMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = CoinChangeProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def filesToGenerate(model: Model, option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(model, option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object CoinChangeDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp", "coinChange") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val CoinChange = new CoinChangeModel().instantiate() + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new CoinChangeMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, CoinChange, topDownWithMemo) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/coinChange/CoinChangeProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/coinChange/CoinChangeProvider.scala new file mode 100644 index 00000000..f83c732f --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/coinChange/CoinChangeProvider.scala @@ -0,0 +1,135 @@ +package org.combinators.archive.unenhancedModels.boilerplate.coinChange + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralArray, LiteralInt, LiteralString, UnitExpression} + +/** + * Partially working implementation of CoinChangeProvider. + * + * 1. Only generates a single test case since the amount cannot be part of test case + * 2. Generates code that must have "fix_topdown.py" applied to it, to ensure code has import java.util.* + * 3. Even then, memo is not generated as a field. + * + * A good start, however. + */ +trait CoinChangeProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTestsCoinChange(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("test1", LiteralArray(Array(1,2,5)), LiteralInt(3), LiteralString("test")) // HACK: amount (11) is not here! + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralArray => lt.literal + case _ => ??? // error in all other circumstances + } + + val dimensions = example.inputType match { + case la: LiteralArray => + la.dimensions + case _ => Seq.empty + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + solType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + + expr <- create_int_nd_array(input_value, dimensions) + variable <- impParadigm.imperativeCapabilities.declareVar(names.mangle("test"), arrayType, Some(expr)) + eleven <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 11) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(variable, eleven)) + + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestsCoinChange(implementation), names.mangle("DP")) + } yield () + } +} + +object CoinChangeProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): CoinChangeProvider.WithParadigm[base.type] = + new CoinChangeProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/fibonacci/FibonacciMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/fibonacci/FibonacciMainJava.scala new file mode 100644 index 00000000..ddbcb94a --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/fibonacci/FibonacciMainJava.scala @@ -0,0 +1,127 @@ +package org.combinators.archive.unenhancedModels.boilerplate.fibonacci + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} +import org.combinators.models._ +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class FibonacciMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = FibonacciProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object FibonacciMainDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val choice = if (args.length == 1) { + args(0).toLowerCase() match { + case "topdown" => topDown + case "topdownwithmemo" => topDownWithMemo + case "bottomup" => bottomUp + case _ => ??? + } + } else { + bottomUp + } + + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + // Fibonacci has a single integer argument + val bound = List(ArgExpression(0, "n", IntegerType(), "i")) + + // COULD be inferred from the ArgExpression list, but this lets us name variable to use in iterator + val n: IteratorExpression = IteratorExpression(0, "i") // only one argument, i + + val im1 = SubtractionExpression(n, one) + val im2 = SubtractionExpression(n, two) + + val Fib = new Model("Fibonacci", + bound, + cases = List( + ( Some(n == zero), zero ), + ( Some(n == one), one ), + ( None, SubproblemExpression(Seq(im1)) + SubproblemExpression(Seq(im2)) ) + ) + ) + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new FibonacciMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, Fib, choice) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/fibonacci/FibonacciProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/fibonacci/FibonacciProvider.scala new file mode 100644 index 00000000..ab0a9617 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/fibonacci/FibonacciProvider.scala @@ -0,0 +1,123 @@ +package org.combinators.archive.unenhancedModels.boilerplate.fibonacci + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, UnitExpression} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait FibonacciProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTestsFibonacci(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + val tests = Seq( + new TestExample("fib0", LiteralInt(0), LiteralInt(0), new UnitExpression), // for now, leave solution as None + new TestExample("fib1", LiteralInt(1), LiteralInt(1), new UnitExpression), + new TestExample("fib2", LiteralInt(2), LiteralInt(1), new UnitExpression), + new TestExample("fib7", LiteralInt(7), LiteralInt(13), new UnitExpression), + new TestExample("fib20", LiteralInt(20), LiteralInt(6765), new UnitExpression), + new TestExample("fib40", LiteralInt(40), LiteralInt(102334155), new UnitExpression) + ) + + println("In FibonacciProvider") + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralInt => lt.literal + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + n_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, input_value) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(n_value), None) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestsFibonacci(implementation), names.mangle("DP")) + } yield () + } +} + +object FibonacciProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): FibonacciProvider.WithParadigm[base.type] = + new FibonacciProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/jumpTo/JumpToMain.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/jumpTo/JumpToMain.scala new file mode 100644 index 00000000..912d2078 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/jumpTo/JumpToMain.scala @@ -0,0 +1,170 @@ +package org.combinators.archive.unenhancedModels.boilerplate.jumpTo + +/** + * An early implementation with unenhanced model. + * + * Test Cases does not compile, because this early implementation had not yet had available the code to properly create arrays + * on which to integrate in a test case. + * + * val targetDirectory = Paths.get("target", "jumpto") + */ +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.FileWithPathPersistable.* +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.* +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + + +class JumpToMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = JumpToMainProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + _ <- dpApproach.implement(model, option) + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +/* + +import java.util.Arrays; + +class Solution { + // Memoization table initialized with -1 + private int[] memo; + + public int numDecodings(String s) { + if (s == null || s.length() == 0 || s.charAt(0) == '0') { + return 0; + } + memo = new int[s.length()]; + // Initialize memo array with -1 to indicate uncomputed states + Arrays.fill(memo, -1); + return decode(s, 0); + } + + private int decode(String s, int index) { + // Base case: If we reach the end of the string, we have found one valid decoding + if (index == s.length()) { + return 1; + } + // If the current character is '0', it cannot be a valid single digit and cannot + // start a two-digit number if it's the first digit, so return 0 ways + if (s.charAt(index) == '0') { + return 0; + } + // If the result for the current index is already computed, return it + if (memo[index] != -1) { + return memo[index]; + } + + int ways = 0; + // Option 1: Decode a single digit + ways += decode(s, index + 1); + + // Option 2: Decode a two-digit number if it is valid (between 10 and 26 inclusive) + if (index + 1 < s.length()) { + int twoDigit = Integer.parseInt(s.substring(index, index + 2)); + if (twoDigit >= 10 && twoDigit <= 26) { + ways += decode(s, index + 2); + } + } + + // Store the result in the memo table before returning + memo[index] = ways; + return ways; + } +} + + + */ + +object JumpToMainDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "jumpto") + + def run(args: List[String]): IO[ExitCode] = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val ascii_zero:LiteralChar = LiteralChar('0') + val two: LiteralInt = LiteralInt(2) + + // what was passed into constructor of the original class + val input:InputExpression = InputExpression("array") // might also need to pass in "type" + + val bound = List(ArgExpression(0, "array", IntegerArrayType(), "i")) + + val n: IteratorExpression = IteratorExpression(0, "i") // only one argument, n + + val JumpTo = new Model("JumpTo", + bound, + cases = List( + // array.length()-1 < n + ( Some(ArrayLengthExpression(input) - one < n), zero), + // array.length()-1 = n + ( Some(ArrayLengthExpression(input) - one == n), zero), + // HACK == helper(n-1) + ( None, SubproblemExpression(Seq(n - one))) + ) + ) + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new JumpToMainJava() } + _ <- IO { println("[OK]") } + + // pass in TOP DOWN + result <- main.runDirectToDisc(targetDirectory, JumpTo, topDown) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/jumpTo/JumpToMainProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/jumpTo/JumpToMainProvider.scala new file mode 100644 index 00000000..9d39b457 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/jumpTo/JumpToMainProvider.scala @@ -0,0 +1,122 @@ +package org.combinators.archive.unenhancedModels.boilerplate.jumpTo + +/** + * An early implementation with unenhanced model. + * + * Test Cases does not compile, because this early implementation had not yet had available the code to properly create arrays + * on which to integrate in a test case. + */ +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.TestExample +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, UnitExpression} + +trait JumpToMainProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm.* + import syntax.* + + // Specific examples hard coded for Int input and Int output + def makeJumpToMain(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities.* + import paradigm.methodBodyCapabilities.* + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + // not sure what to write here, yet... + new TestExample("replaceme", LiteralInt(0), LiteralInt(0), new UnitExpression), // for now, leave solution as None + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralInt => lt.literal + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + n_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, input_value) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(n_value)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeJumpToMain(implementation), names.mangle("DP")) + } yield () + } +} + +object JumpToMainProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): JumpToMainProvider.WithParadigm[base.type] = + new JumpToMainProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/knapsack/KnapsackMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/knapsack/KnapsackMainJava.scala new file mode 100644 index 00000000..a71da7df --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/knapsack/KnapsackMainJava.scala @@ -0,0 +1,96 @@ +package org.combinators.archive.unenhancedModels.boilerplate.knapsack + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.knapsack.KnapsackModel +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class KnapsackMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = KnapsackProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def filesToGenerate(model: Model, option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(model, option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object KnapsackDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val Knapsack = new KnapsackModel().instantiate() + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new KnapsackMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, Knapsack, bottomUp) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/knapsack/KnapsackProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/knapsack/KnapsackProvider.scala new file mode 100644 index 00000000..fa076e98 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/knapsack/KnapsackProvider.scala @@ -0,0 +1,133 @@ +package org.combinators.archive.unenhancedModels.boilerplate.knapsack + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{ArgumentType, LiteralExpression, LiteralInt, LiteralString} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait KnapsackProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + case class KnapsackInput() extends ArgumentType + class KnapsackTestCase(val values:Array[Int], val dim1:Int, val maxWeight: Int) extends LiteralExpression { + def tpe:ArgumentType = KnapsackInput() + } + + // Specific examples hard coded for Int input and Int output + def makeTestsKnapsack(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("test1", new KnapsackTestCase(Array(4, 1, 5, 2, 1, 3 ), 3, 4), LiteralInt(3), LiteralString("answer")), + new TestExample("test1", new KnapsackTestCase(Array(10, 16, 8, 8, 9, 4, 4, 2 ), 4, 33), LiteralInt(30), LiteralString("answer")), + new TestExample("test1", new KnapsackTestCase(Array(2, 300, 1, 200, 5,400, 3,500 ), 4, 10), LiteralInt(1100), LiteralString("answer")) + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case pair: KnapsackTestCase => (pair.values, pair.dim1, pair.maxWeight) + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + translated_vals <- forEach(input_value._1) { value => + for { + reified_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, value) + } yield reified_value + } + intType <- toTargetLanguageType(TypeRep.Int) + array <- array.arrayCapabilities.create(intType, Seq(input_value._2, 2), translated_vals) // second dimension is always 2 + ar3 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, input_value._3) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(array, ar3)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestsKnapsack(implementation), names.mangle("DP")) + } yield () + } +} + +object KnapsackProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): KnapsackProvider.WithParadigm[base.type] = + new KnapsackProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/minEditDistance/MinEditDistanceMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/minEditDistance/MinEditDistanceMainJava.scala new file mode 100644 index 00000000..8b05022e --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/minEditDistance/MinEditDistanceMainJava.scala @@ -0,0 +1,94 @@ +package org.combinators.archive.unenhancedModels.boilerplate.minEditDistance + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.twoSequences.MinimumEditDistanceModel +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class MinEditDistanceMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = MinEditDistanceProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object MinEditDistanceDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val MED = new MinimumEditDistanceModel().instantiate() + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new MinEditDistanceMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, MED, topDownWithMemo) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/minEditDistance/MinEditDistanceProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/minEditDistance/MinEditDistanceProvider.scala new file mode 100644 index 00000000..b0fcfa6b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/minEditDistance/MinEditDistanceProvider.scala @@ -0,0 +1,121 @@ +package org.combinators.archive.unenhancedModels.boilerplate.minEditDistance + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, LiteralString} +import org.combinators.archive.unenhancedModels.models.LiteralStringPair + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait MinEditDistanceProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTestsMinEditDistance(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("fib0", LiteralStringPair("ACTG", "CGATC"), LiteralInt(2), LiteralString("AC")) // for now, leave solution as None + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralStringPair => (lt.string1, lt.string2) + case _ => ??? // error in all other circumstances + } + + val expected_value = example.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + s1_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._1) + s2_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._2) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(s1_value, s2_value)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTestsMinEditDistance(implementation), names.mangle("DP")) + } yield () + } +} + +object MinEditDistanceProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): MinEditDistanceProvider.WithParadigm[base.type] = + new MinEditDistanceProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/threeStringLCS/ThreeStringLCSMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/threeStringLCS/ThreeStringLCSMainJava.scala new file mode 100644 index 00000000..c3f337a6 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/threeStringLCS/ThreeStringLCSMainJava.scala @@ -0,0 +1,92 @@ +package org.combinators.archive.unenhancedModels.boilerplate.threeStringLCS + +/** + * Includes first attempt to generate retrieve() method, but it won't compile. + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.other.ThreeStringLCSModel +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class ThereStringLCSMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = ThreeStringLCSProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object TSLCSDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "archive", "tslcs") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val tslcs = new ThreeStringLCSModel().instantiate() + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new ThereStringLCSMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, tslcs, bottomUp) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/threeStringLCS/ThreeStringLCSProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/threeStringLCS/ThreeStringLCSProvider.scala new file mode 100644 index 00000000..5207a3cb --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/threeStringLCS/ThreeStringLCSProvider.scala @@ -0,0 +1,122 @@ +package org.combinators.archive.unenhancedModels.boilerplate.threeStringLCS + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, LiteralString} +import org.combinators.archive.unenhancedModels.models.LiteralStringTriple + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait ThreeStringLCSProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTests(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("test1", LiteralStringTriple("AGGT12", "12TXAYB", "12XBA"), LiteralInt(2), LiteralString("AC")) // for now, leave solution as None + ) + + for { + assert_statements <- forEach(tests) { example => + + val input_value = example.inputType match { + case lt: LiteralStringTriple => (lt.string1, lt.string2, lt.string3) + case _ => ??? // error in all other circumstances + } + + val sol_gen_value = example.answer match { + case lit:LiteralInt => paradigm.methodBodyCapabilities.reify(TypeRep.Int, lit.literal) + case _ => ??? + } + + for { + tslcsType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + s1_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._1) + s2_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._2) + s3_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, input_value._3) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(tslcsType, Seq(s1_value, s2_value, s3_value)) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + tslcs_actual <- apply(computeMethod, Seq.empty) + sol_value <- sol_gen_value + asserteq_tslcs <- asserts.assertionCapabilities.assertEquals(intType, tslcs_actual, sol_value) + + } yield asserteq_tslcs + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTests(implementation), names.mangle("DP")) + } yield () + } +} + +object ThreeStringLCSProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): ThreeStringLCSProvider.WithParadigm[base.type] = + new ThreeStringLCSProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/uncrossedLines/UnenhancedUncrossedLinesMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/uncrossedLines/UnenhancedUncrossedLinesMainJava.scala new file mode 100644 index 00000000..c7e34c29 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/uncrossedLines/UnenhancedUncrossedLinesMainJava.scala @@ -0,0 +1,97 @@ +package org.combinators.archive.unenhancedModels.boilerplate.uncrossedLines + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.archive.unenhancedModels.models.twoSequences.UncrossedLinesModel +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable._ +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.original.Model + +import java.nio.file.{Path, Paths} +import scala.collection.Seq + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class UnenhancedUncrossedLinesMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = UncrossedLinesProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + def filesToGenerate(model:Model, option:GenerationOption):Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, model:Model, option:GenerationOption): IO[Unit] = { + IO { + println("Computing Files...") + val computed = filesToGenerate(model:Model, option:GenerationOption) + println("[OK]") + if (targetDirectory.toFile.exists()) { + println(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + println("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, model:Model, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, model, option) + } yield ExitCode.Success + } +} + +object ULDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp", "unenhancedUncrossedLines") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val UL = new UncrossedLinesModel().instantiate() + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new UnenhancedUncrossedLinesMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, UL, bottomUp) // bottom up not working for some reason.... + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/uncrossedLines/UnenhancedUncrossedLinesProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/uncrossedLines/UnenhancedUncrossedLinesProvider.scala new file mode 100644 index 00000000..cd6dba17 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/boilerplate/uncrossedLines/UnenhancedUncrossedLinesProvider.scala @@ -0,0 +1,126 @@ +package org.combinators.archive.unenhancedModels.boilerplate.uncrossedLines + +import org.combinators.archive.unenhancedModels.models.LiteralArrayPair +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.dp.original.DPObjectOrientedProvider +import org.combinators.models.{LiteralInt, UnitExpression} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait UnenhancedUncrossedLinesProvider extends DPObjectOrientedProvider { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + + // Specific examples hard coded for Int input and Int output + def makeTests(implementation:String, tests: Seq[TestExample] = Seq.empty): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + // NOTE: these tests are in the wrong place, since we defer test gen to later + val tests = Seq( + new TestExample("ucl0", LiteralArrayPair(Array(1, 4, 2), Array(1, 2, 4)), LiteralInt(2), new UnitExpression), // https://leetcode.com/problems/uncrossed-lines/ + new TestExample("ucl1", LiteralArrayPair(Array(2, 5, 1, 2, 5), Array(10, 5, 2, 1, 5, 2)), LiteralInt(3), new UnitExpression), // https://leetcode.com/problems/uncrossed-lines/ + ) + + for { + assert_statements <- forEach(tests) { test => + + val input_value = test.inputType match { + case lt: LiteralArrayPair => (lt.ar1, lt.ar2) + case _ => ??? // error in all other circumstances + } + + val expected_value = test.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + for { + fibType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + + ar1 <- create_int_array(input_value._1) + ar2 <- create_int_array(input_value._2) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(fibType, Seq(ar1, ar2)) + + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + intType <- toTargetLanguageType(TypeRep.Int) + fibn_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, expected_value) + fib_actual <- apply(computeMethod, Seq.empty) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(intType, fib_actual, fibn_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + + override def makeTestCase(implementation:String): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(makeTests(implementation), names.mangle("DP")) + } yield () + } +} + +object UncrossedLinesProvider { + type WithParadigm[P <: AnyParadigm] = DPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): UncrossedLinesProvider.WithParadigm[base.type] = + new UnenhancedUncrossedLinesProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/Expression.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/Expression.scala new file mode 100644 index 00000000..9325f667 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/Expression.scala @@ -0,0 +1,29 @@ +package org.combinators.archive.unenhancedModels.models + +import org.combinators.models.{ArgumentType, LiteralExpression} + +/** These are archived Literal expressions, only to be used by archive, older vode. */ +case class StringPairType() extends ArgumentType +case class LiteralStringPair(string1:String, string2:String) extends LiteralExpression { + def tpe:ArgumentType = StringPairType() +} + +case class StringTripleType() extends ArgumentType +case class LiteralStringTriple(string1:String, string2:String, string3:String) extends LiteralExpression { + def tpe:ArgumentType = StringTripleType() +} + +case class LiteralPairType() extends ArgumentType +case class LiteralPair(val1:Int, val2:Int) extends LiteralExpression { + def tpe:ArgumentType = LiteralPairType() +} + +case class LiteralTripleType() extends ArgumentType +case class LiteralTriple(val1: Int, val2: Int, val3: Int) extends LiteralExpression { + def tpe: ArgumentType = LiteralTripleType() +} + +case class IntegerArrayPair() extends ArgumentType +case class LiteralArrayPair(ar1: Array[Int], ar2: Array[Int]) extends LiteralExpression { + def tpe: ArgumentType = IntegerArrayPair() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/grid/UniquePathsModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/grid/UniquePathsModel.scala new file mode 100644 index 00000000..e674e2d4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/grid/UniquePathsModel.scala @@ -0,0 +1,32 @@ +package org.combinators.archive.unenhancedModels.models.grid + +import org.combinators.models._ +import org.combinators.models.original.Model + +class UniquePathsModel { + def instantiate(): Model = { + val m = ArgExpression(0, "m", IntegerType(), "r") + val n = ArgExpression(1, "n", IntegerType(), "c") + val bounds = List(m, n) + + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val UP: Model = new Model( + "Unique Paths", + bounds = bounds, + cases = List( + ( + Some(n == zero || m == zero), + one + ), + ( + None, + SubproblemExpression(Seq(m - one, n)) + SubproblemExpression(Seq(m, n - one)) + ) + ) + ) + + UP + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/knapsack/CoinChangeModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/knapsack/CoinChangeModel.scala new file mode 100644 index 00000000..f02a82a4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/knapsack/CoinChangeModel.scala @@ -0,0 +1,41 @@ +package org.combinators.archive.unenhancedModels.models.knapsack + +import org.combinators.models._ +import org.combinators.models.original.Model + +class CoinChangeModel { + def instantiate(): Model = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val arrayArg = ArgExpression(0, "coins", IntegerArrayType(), "c") + val amount = ArgExpression(1, "amount", IntegerType(), "a") + + val c: IteratorExpression = IteratorExpression(0, "c") + val a: IteratorExpression = IteratorExpression(1, "a") + + val coinscm1 = ArrayElementExpression(arrayArg,c-one) + + + val Knapsack: Model = new Model("CoinChange", + List(arrayArg,amount), + cases = List( + (Some(a == zero), zero), + (Some(c == zero), LiteralInt(1073741823)), + (Some(amount < coinscm1), + SubproblemExpression(Seq(c-one)) + ), + ( + None, + MinExpression( + SubproblemExpression(Seq(c, amount - coinscm1)) + one, + SubproblemExpression(Seq(c - one, amount))) + ) + ) + ) + + Knapsack + + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/knapsack/KnapsackModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/knapsack/KnapsackModel.scala new file mode 100644 index 00000000..cd757b8e --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/knapsack/KnapsackModel.scala @@ -0,0 +1,44 @@ +package org.combinators.archive.unenhancedModels.models.knapsack + +import org.combinators.models._ +import org.combinators.models.original.Model + +class KnapsackModel { + def instantiate(): Model = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + //the array should be 2d + val arrayArg = ArgExpression(0, "arr", IntegerArray2DType(), "i") + val weight = ArgExpression(1, "W", IntegerType(), "w") + + val i: IteratorExpression = IteratorExpression(0, "i") + val w: IteratorExpression = IteratorExpression(1, "w") + + val weightim1= ArrayElementExpression(ArrayElementExpression(arrayArg, i - one), zero) + val valueim1= ArrayElementExpression(ArrayElementExpression(arrayArg, i - one), one) + + + val Knapsack: Model = new Model("Knapsack", + List(arrayArg,weight), + cases = List( + (Some(i == zero), zero), + (Some(w == zero), zero), + ( + None, + MaxExpression( + SubproblemExpression(List(i - one, w)), + TernaryExpression( + weightim1 < w, + valueim1 + SubproblemExpression(List(i - one, w - weightim1)), + zero) + ) + ) + ) + ) + + Knapsack + + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/oneSequence/FibonacciModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/oneSequence/FibonacciModel.scala new file mode 100644 index 00000000..bd5c3ff4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/oneSequence/FibonacciModel.scala @@ -0,0 +1,29 @@ +package org.combinators.archive.unenhancedModels.models.oneSequence + +import org.combinators.models._ +import org.combinators.models.original.Model + +class FibonacciModel { + def instantiate(): Model = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + val bound = List(ArgExpression(0, "n", IntegerType(), "i")) + + val i: IteratorExpression = IteratorExpression(0, "i") + + val Fib: Model = new Model("Fibonacci", + bound, + cases = List( + (Some(i == zero), zero), + (Some(i == one), one), + (None, SubproblemExpression(Seq(i - one)) + SubproblemExpression(Seq(i - two))) + ) + ) + + Fib + + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/oneSequence/MaxSubarrayModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/oneSequence/MaxSubarrayModel.scala new file mode 100644 index 00000000..6d753377 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/oneSequence/MaxSubarrayModel.scala @@ -0,0 +1,32 @@ +package org.combinators.archive.unenhancedModels.models.oneSequence + +import org.combinators.models._ +import org.combinators.models.original.Model + +class MaxSubarrayModel { + def instantiate(): Model = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val bounds = List(ArrayLengthExpression(ArgExpression(0, "nums", IntegerType(), "i") ), 2) + val fakeBound = List(ArgExpression(0, "nums", IntegerType(), "m")) // not sure if these are right. + + val i: IteratorExpression = IteratorExpression(0, "i") + val m: IteratorExpression = IteratorExpression(0, "m") + + val cur = ArrayElementExpression(ArgExpression(0, "nums", IntegerType(), "m"), i) + + val MaxSubarray: Model = new Model("MaxSubarray", + fakeBound, + cases = List( + (Some(i == zero), cur), + (Some(m == zero), MaxExpression(SubproblemExpression(Seq(i - one, zero)) + cur, cur)), + (None, MaxExpression(SubproblemExpression(Seq(i, zero)), SubproblemExpression(Seq(i - one, one)))) + ) + ) + + MaxSubarray + + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/other/ThreeStringLCSModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/other/ThreeStringLCSModel.scala new file mode 100644 index 00000000..9e26403b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/other/ThreeStringLCSModel.scala @@ -0,0 +1,45 @@ +package org.combinators.archive.unenhancedModels.models.other + +import org.combinators.models._ +import org.combinators.models.original.Model + +class ThreeStringLCSModel { + def instantiate(): Model = { + val s1 = ArgExpression(0, "s1", StringType(), "i") + val s2 = ArgExpression(1, "s2", StringType(), "j") + val s3 = ArgExpression(2, "s3", StringType(), "k") + + val bounds = List(s1, s2, s3) + + val i: IteratorExpression = IteratorExpression(0, "i") + val j: IteratorExpression = IteratorExpression(1, "j") + val k: IteratorExpression = IteratorExpression(2, "k") + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val TSLCS: Model = new Model( + "ThreeStringLCS", + bounds = bounds, + cases = List( + (Some(i == zero || j == zero || k == zero), zero), + ( + Some(CharAtExpression(s1, i - one) == CharAtExpression(s2, j - one) && CharAtExpression(s1, i - one) == CharAtExpression(s3, k - one)), + SubproblemExpression(Seq(i - one, j - one, k - one)) + one + ), + ( + None, + MaxExpression( + SubproblemExpression(Seq(i - one, j, k)), + MaxExpression( + SubproblemExpression(Seq(i, j - one, k)), + SubproblemExpression(Seq(i, j, k - one)) + ) + ) + ) + ) + ) + + TSLCS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/DistinctSubsequences.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/DistinctSubsequences.scala new file mode 100644 index 00000000..1505b3d2 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/DistinctSubsequences.scala @@ -0,0 +1,35 @@ +package org.combinators.archive.unenhancedModels.models.twoSequences + +import org.combinators.models._ +import org.combinators.models.original.Model + +class DistinctSubsequences { + def instantiate(): Model = { + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val boundZero: Expression = ArrayLengthExpression(s1) + val boundOne: Expression = ArrayLengthExpression(s2) + val bounds = List(s1, s2) + + val r: IteratorExpression = IteratorExpression(0, "r") + val c: IteratorExpression = IteratorExpression(1, "c") + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val DS: Model = new Model( + "Distinct Subsequences", + bounds = bounds, + cases = List( + (Some(c == zero), one), + (Some(EqualExpression(CharAtExpression(s1, r - one), CharAtExpression(s2, c - one), CharType())), + SubproblemExpression(Seq(r - one, c - one)) + SubproblemExpression(Seq(r - one, c)) + ), + (None, SubproblemExpression(Seq(r - one, c))) + ) + ) + + DS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/LongestCommonSubsequenceModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/LongestCommonSubsequenceModel.scala new file mode 100644 index 00000000..864b4087 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/LongestCommonSubsequenceModel.scala @@ -0,0 +1,41 @@ +package org.combinators.archive.unenhancedModels.models.twoSequences + +import org.combinators.models._ +import org.combinators.models.original.Model + +class LongestCommonSubsequenceModel { + def instantiate(): Model = { + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val boundZero: Expression = StringLengthExpression(s1) + val boundOne: Expression = StringLengthExpression(s2) + val bounds = List(s1, s2) + + val r: IteratorExpression = IteratorExpression(0, "r") + val c: IteratorExpression = IteratorExpression(1, "c") + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val LCS: Model = new Model("PrototypeLCS", // cannot have space in the name since this becomes a file + bounds = bounds, + cases = List( + (Some(r == zero), zero), + (Some(c == zero), zero), + (Some(CharAtExpression(s1, r-one) == CharAtExpression(s2, c-one)), + SubproblemExpression(Seq(r - one, c - one)) + one + ), + ( + None, + MaxExpression( + SubproblemExpression(Seq(SubtractionExpression(r, one), c)), + SubproblemExpression(Seq(r, c - one)) + ) + ) + ) + ) + + LCS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/MinimumEditDistanceModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/MinimumEditDistanceModel.scala new file mode 100644 index 00000000..1e7b97f1 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/MinimumEditDistanceModel.scala @@ -0,0 +1,46 @@ +package org.combinators.archive.unenhancedModels.models.twoSequences + +import org.combinators.models._ +import org.combinators.models.original.Model + +class MinimumEditDistanceModel { + def instantiate(): Model = { + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val boundZero: Expression = ArrayLengthExpression(s1) + val boundOne: Expression = ArrayLengthExpression(s2) + val bounds = List(s1, s2) + + val r: IteratorExpression = IteratorExpression(0, "r") + val c: IteratorExpression = IteratorExpression(1, "c") + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + def MED: Model = new Model( + "MinimumEditDistance", + bounds = bounds, + cases = List( + (Some(r == zero), c), + (Some(c == zero), r), + ( + Some(EqualExpression(CharAtExpression(s1, r - one), CharAtExpression(s2, c - one), CharType())), + SubproblemExpression(Seq(r - one, c - one)) + ), + ( + None, + one + MinExpression( + MinExpression( + SubproblemExpression(Seq(r - one, c)), + SubproblemExpression(Seq(r, c - one)) + ), + SubproblemExpression(Seq(r - one, c - one)) + ) + ) + ) + ) + + MED + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/NeedlemanWunschSequenceAlignmentModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/NeedlemanWunschSequenceAlignmentModel.scala new file mode 100644 index 00000000..6e4ed6c1 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/NeedlemanWunschSequenceAlignmentModel.scala @@ -0,0 +1,51 @@ +package org.combinators.archive.unenhancedModels.models.twoSequences + +import org.combinators.models._ +import org.combinators.models.original.Model + +@deprecated(message = "Needs to be upgraded to Enhanced Model, since gapPenalty (and others) does not generate properly") +class NeedlemanWunschSequenceAlignmentModel { + def instantiate(): Model = { + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + val matchBonus = ArgExpression(2, "matchBonus", IntegerType(), "") // not iterable + val mismatchPenalty = ArgExpression(3, "mismatchPenalty", IntegerType(), "") // not iterable + val gapPenalty = ArgExpression(4, "gapPenalty", IntegerType(), "") // not iterable + + val boundZero: Expression = StringLengthExpression(s1) + val boundOne: Expression = StringLengthExpression(s2) + val bounds = List(s1, s2) + + val r: IteratorExpression = IteratorExpression(0, "r") + val c: IteratorExpression = IteratorExpression(1, "c") + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val score = TernaryExpression( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + matchBonus, + mismatchPenalty + ) + + val NWSA: Model = new Model( + "PrototypeNWSA", + bounds = bounds, + cases = List( + (Some(c == zero), r * gapPenalty), + (Some(r == zero), c * gapPenalty), + (None, + MaxExpression( + SubproblemExpression(Seq(r - one, c - one)) + score, + MaxExpression( + SubproblemExpression(Seq(r - one, c)) + gapPenalty, + SubproblemExpression(Seq(r, c - one)) + gapPenalty + ) + ) + ) + ) + ) + + NWSA + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/UncrossedLinesModel.scala b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/UncrossedLinesModel.scala new file mode 100644 index 00000000..22a213d4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/archive/unenhancedModels/models/twoSequences/UncrossedLinesModel.scala @@ -0,0 +1,52 @@ +package org.combinators.archive.unenhancedModels.models.twoSequences + +import org.combinators.models._ +import org.combinators.models.original.Model + +class UncrossedLinesModel { + def instantiate(): Model = { + val nums1 = ArgExpression(0, "A1", IntegerArrayType(), "r") + val nums2 = ArgExpression(1, "A2", IntegerArrayType(), "c") + + val boundZero: Expression = ArrayLengthExpression(nums1) + val boundOne: Expression = ArrayLengthExpression(nums2) + val bounds = List(nums1, nums2) + + val r: IteratorExpression = IteratorExpression(0, "r") + val c: IteratorExpression = IteratorExpression(1, "c") + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val UL: Model = new Model( + "PrototypeUL", + bounds, + cases = List( + ( + Some(r == zero), + zero + ), + ( + Some(c == zero), + zero + ), + ( + Some(ArrayElementExpression(nums1, SubtractionExpression(r, one)) == ArrayElementExpression(nums2, SubtractionExpression(c, one))), + AdditionExpression( + SubproblemExpression(Seq(r - one, c - one)), + one + ) + ), + ( + None, + MaxExpression( + SubproblemExpression(Seq(r, c - one)), + SubproblemExpression(Seq(r - one, c)) + ) + ), + ) + ) + + UL + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/CountSquaresMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/CountSquaresMain.scala new file mode 100644 index 00000000..bdcd36c0 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/CountSquaresMain.scala @@ -0,0 +1,31 @@ +package org.combinators.boilerplate.grid + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models._ +import org.combinators.models.enhancedModels.grid.CountSquares + +trait CountSquaresApp { + def tests = Seq( + new TestExample("cs1", LiteralArray(Array(0,1,1,1, 1,1,1,1, 0,1,1,1), Seq(3,4)), LiteralInt(15), new UnitExpression), + new TestExample("cs2", LiteralArray(Array(0,0,0,0, 0,0,0,0, 0,0,0,0), Seq(3,4)), LiteralInt(0), new UnitExpression) + ) + val model: EnhancedModel = new CountSquares().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class CountSquaresMainJava extends EnhancedDPMainJava with CountSquaresApp { + override def constructApp(): EnhancedDPMainJava = new CountSquaresMainJava() +} +class CountSquaresMainScala extends EnhancedDPMainScala with CountSquaresApp { + override def constructApp(): EnhancedDPMainScala = new CountSquaresMainScala() +} + +// need objects to be able to execute as IOApp +object CountSquaresScalaToDiskMain extends EnhancedDPMainScala with CountSquaresApp { + override def constructApp(): EnhancedDPMainScala = new CountSquaresMainScala() +} +object CountSquaresJavaToDiskMain extends EnhancedDPMainJava with CountSquaresApp { + override def constructApp(): EnhancedDPMainJava = new CountSquaresMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/GridWithObstaclesMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/GridWithObstaclesMain.scala new file mode 100644 index 00000000..8531b193 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/GridWithObstaclesMain.scala @@ -0,0 +1,39 @@ +package org.combinators.boilerplate.grid + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.models.* +import org.combinators.models.enhancedModels.grid.GridWithObstacles + +trait GridWithObstaclesApp { + def tests = Seq( + new TestExample("gwo1", LiteralArray(Array(0,0,0,0, + 0,0,0,0, + 0,0,0,0), Seq(3,4)), LiteralInt(10), new UnitExpression) , // no obstacles + new TestExample("gwo2", LiteralArray(Array(0,0,0,0, + 0,1,1,0, + 0,0,0,0), Seq(3,4)), LiteralInt(2), new UnitExpression), // around edges only + new TestExample("gwo2", LiteralArray(Array(0,0,0,0,0,0, + 0,1,1,0,0,0, + 0,0,0,1,1,0, + 0,1,1,0,0,0, + 0,0,0,0,0,0), Seq(5,6)), LiteralInt(4), new UnitExpression), // more complex + ) + val model: EnhancedModel = new GridWithObstacles().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class GridWithObstaclesMainJava extends EnhancedDPMainJava with GridWithObstaclesApp { + override def constructApp(): EnhancedDPMainJava = new GridWithObstaclesMainJava() +} +class GridWithObstaclesMainScala extends EnhancedDPMainScala with GridWithObstaclesApp { + override def constructApp(): EnhancedDPMainScala = new GridWithObstaclesMainScala() +} + +// need objects to be able to execute as IOApp +object GridWithObstaclesScalaToDiskMain extends EnhancedDPMainScala with GridWithObstaclesApp { + override def constructApp(): EnhancedDPMainScala = new GridWithObstaclesMainScala() +} +object GridWithObstaclesJavaToDiskMain extends EnhancedDPMainJava with GridWithObstaclesApp { + override def constructApp(): EnhancedDPMainJava = new GridWithObstaclesMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/MinPathSumMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/MinPathSumMain.scala new file mode 100644 index 00000000..e4a93e00 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/MinPathSumMain.scala @@ -0,0 +1,36 @@ +package org.combinators.boilerplate.grid + +import cats.effect.{ExitCode, IO, IOApp} +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.grid.MinPathSum + +import java.nio.file.{Path, Paths} + +trait MinPathSumApp { + + val tests = Seq( + new TestExample("mps1", LiteralArray(Array(1,3,1, 1,5,1, 4,2,1), Seq(3,3)), LiteralInt(7), new UnitExpression), + new TestExample("mps2", LiteralArray(Array(1,2,3, 4,5,6), Seq(2,3)), LiteralInt(12), new UnitExpression), + ) + + val model: EnhancedModel = new MinPathSum().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class MinPathSumMainJava extends EnhancedDPMainJava with MinPathSumApp { + override def constructApp(): EnhancedDPMainJava = new MinPathSumMainJava() +} +class MinPathSumMainScala extends EnhancedDPMainScala with MinPathSumApp { + override def constructApp(): EnhancedDPMainScala = new MinPathSumMainScala() +} + +// need objects to be able to execute as IOApp +object MinPathSumScalaToDiskMain extends EnhancedDPMainScala with MinPathSumApp { + override def constructApp(): EnhancedDPMainScala = new MinPathSumMainScala() +} +object MinPathSumJavaToDiskMain extends EnhancedDPMainJava with MinPathSumApp { + override def constructApp(): EnhancedDPMainJava = new MinPathSumMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/NumberPathsWithKCoins.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/NumberPathsWithKCoins.scala new file mode 100644 index 00000000..26ce5f7f --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/NumberPathsWithKCoins.scala @@ -0,0 +1,32 @@ +package org.combinators.boilerplate.grid + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.models.* +import org.combinators.models.enhancedModels.grid.NumberPathsWithKCoins + +trait NumberPathsWithKCoinsApp { + def tests = Seq( + new TestExample("npk1", LiteralTuple(LiteralArray(Array(1, 2, 3, + 4, 6, 5, + 3, 2, 1), Seq(3,3)), LiteralInt(12)), LiteralInt(10), new UnitExpression) , // 12 total count + + ) + val model: EnhancedModel = new NumberPathsWithKCoins().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class NumberPathsWithKCoinsMainJava extends EnhancedDPMainJava with NumberPathsWithKCoinsApp { + override def constructApp(): EnhancedDPMainJava = new NumberPathsWithKCoinsMainJava() +} +class NumberPathsWithKCoinsMainScala extends EnhancedDPMainScala with NumberPathsWithKCoinsApp { + override def constructApp(): EnhancedDPMainScala = new NumberPathsWithKCoinsMainScala() +} + +// need objects to be able to execute as IOApp +object NumberPathsWithKCoinsScalaToDiskMain extends EnhancedDPMainScala with NumberPathsWithKCoinsApp { + override def constructApp(): EnhancedDPMainScala = new NumberPathsWithKCoinsMainScala() +} +object NumberPathsWithKCoinsJavaToDiskMain extends EnhancedDPMainJava with NumberPathsWithKCoinsApp { + override def constructApp(): EnhancedDPMainJava = new NumberPathsWithKCoinsMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/README.txt b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/README.txt new file mode 100644 index 00000000..e969eaff --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/README.txt @@ -0,0 +1,13 @@ +https://www.geeksforgeeks.org/dsa/dp-on-grids/ + +1. Count number of Paths from the Top-Left Cell to the Bottom-Right cell of the grid +2. Count number of Paths from the Top-Left Cell to the Bottom Right cell of the grid with obstructions +3. Minimum Steps to reach any of the boundary edges of a matrix +4. Minimum Steps to reach any of the boundary edges of a matrix +5. Minimum Path Sum in a triangle +6. Maximum Path Sum from the first row to the last row of the grid +7. Finding Maximum Size Square Sub-matrix with all 1s +8. Finding Maximum Sum Rectangle in a 2D Grid +9. Number of ways to reach the destination in the grid with exactly K coins (3D DP) +10. Maximum objects to collect starting from top left and top right cells of the grid (3D DP) +11. Maximum objects to collect starting from top left to bottom right cell and then from bottom right back to top left cell of the grid (3D DP) diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/UniquePathsMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/UniquePathsMain.scala new file mode 100644 index 00000000..a66b96bc --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/grid/UniquePathsMain.scala @@ -0,0 +1,35 @@ +package org.combinators.boilerplate.grid + +import cats.effect.{ExitCode, IO, IOApp} +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.grid.UniquePaths + +import java.nio.file.{Path, Paths} + +trait UniquePathsApp { + val tests = Seq( + new TestExample("up1", LiteralTuple(LiteralInt(3), LiteralInt(7)), LiteralInt(28), new UnitExpression), + new TestExample("up2", LiteralTuple(LiteralInt(3), LiteralInt(2)), LiteralInt(3), new UnitExpression), + ) + + val model: EnhancedModel = new UniquePaths().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class UniquePathsMainJava extends EnhancedDPMainJava with UniquePathsApp { + override def constructApp(): EnhancedDPMainJava = new UniquePathsMainJava() +} +class UniquePathsMainScala extends EnhancedDPMainScala with UniquePathsApp { + override def constructApp(): EnhancedDPMainScala = new UniquePathsMainScala() +} + +// need objects to be able to execute as IOApp +object UniquePathsScalaToDiskMain extends EnhancedDPMainScala with UniquePathsApp { + override def constructApp(): EnhancedDPMainScala = new UniquePathsMainScala() +} +object UniquePathsJavaToDiskMain extends EnhancedDPMainJava with UniquePathsApp { + override def constructApp(): EnhancedDPMainJava = new UniquePathsMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/BellNumberMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/BellNumberMain.scala new file mode 100644 index 00000000..b05138cf --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/BellNumberMain.scala @@ -0,0 +1,39 @@ +package org.combinators.boilerplate.integer + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.integer.BellNumber + +trait BellNumberApp { + val tests = Seq( + new TestExample("bn1", LiteralInt(3), LiteralInt(5), new UnitExpression), // https://en.wikipedia.org/wiki/Bell_number + new TestExample("bn2", LiteralInt(2), LiteralInt(2), new UnitExpression), + new TestExample("bn3", LiteralInt(5), LiteralInt(52), new UnitExpression), + ) + + val model: EnhancedModel = new BellNumber().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class BellNumberMainJava extends EnhancedDPMainJava with BellNumberApp { + override def constructApp(): EnhancedDPMainJava = new BellNumberMainJava() +} +class BellNumberMainScala extends EnhancedDPMainScala with BellNumberApp { + override def constructApp(): EnhancedDPMainScala = new BellNumberMainScala() +} + +// need objects to be able to execute as IOApp +object BellNumberScalaToDiskMain extends EnhancedDPMainScala with BellNumberApp { + override def constructApp(): EnhancedDPMainScala = new BellNumberMainScala() +} +object BellNumberJavaToDiskMain extends EnhancedDPMainJava with BellNumberApp { + override def constructApp(): EnhancedDPMainJava = new BellNumberMainJava() +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/DiceThrowMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/DiceThrowMain.scala new file mode 100644 index 00000000..f047dfc0 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/DiceThrowMain.scala @@ -0,0 +1,39 @@ +package org.combinators.boilerplate.integer + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.integer.DiceThrow + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +trait DiceThrowApp { + val tests = Seq( + new TestExample("dt1", LiteralTuple(LiteralInt(6), LiteralInt(3), LiteralInt(12)), LiteralInt(25), new UnitExpression) // https://www.geeksforgeeks.org/dsa/dice-throw-dp-30/ + ) + val model: EnhancedModel = new DiceThrow().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class DiceThrowMainJava extends EnhancedDPMainJava with DiceThrowApp { + override def constructApp(): EnhancedDPMainJava = new DiceThrowMainJava() +} +class DiceThrowMainScala extends EnhancedDPMainScala with DiceThrowApp { + override def constructApp(): EnhancedDPMainScala = new DiceThrowMainScala() +} + +// need objects to be able to execute as IOApp +object DiceThrowScalaToDiskMain extends EnhancedDPMainScala with DiceThrowApp { + override def constructApp(): EnhancedDPMainScala = new DiceThrowMainScala() +} +object DiceThrowJavaToDiskMain extends EnhancedDPMainJava with DiceThrowApp { + override def constructApp(): EnhancedDPMainJava = new DiceThrowMainJava() +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/FibonacciMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/FibonacciMain.scala new file mode 100644 index 00000000..2720526d --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/FibonacciMain.scala @@ -0,0 +1,44 @@ +package org.combinators.boilerplate.integer + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.integer.Fibonacci + +/** + * Uses enhanced DP Provide + */ +trait FibonacciApp { + val tests = Seq( + new TestExample("fib0", LiteralInt(0), LiteralInt(0), new UnitExpression), // for now, leave solution as None + new TestExample("fib1", LiteralInt(1), LiteralInt(1), new UnitExpression), + new TestExample("fib2", LiteralInt(2), LiteralInt(1), new UnitExpression), + new TestExample("fib7", LiteralInt(7), LiteralInt(13), new UnitExpression), + new TestExample("fib20", LiteralInt(20), LiteralInt(6765), new UnitExpression), + new TestExample("fib40", LiteralInt(40), LiteralInt(102334155), new UnitExpression) // Takes some time! + ) + + val model: EnhancedModel = new Fibonacci().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class FibonacciMainJava extends EnhancedDPMainJava with FibonacciApp { + override def constructApp(): EnhancedDPMainJava = new FibonacciMainJava() +} +class FibonacciMainScala extends EnhancedDPMainScala with FibonacciApp { + override def constructApp(): EnhancedDPMainScala = new FibonacciMainScala() +} + +// need objects to be able to execute as IOApp +object FibonacciScalaToDiskMain extends EnhancedDPMainScala with FibonacciApp { + override def constructApp(): EnhancedDPMainScala = new FibonacciMainScala() +} +object FibonacciJavaToDiskMain extends EnhancedDPMainJava with FibonacciApp { + override def constructApp(): EnhancedDPMainJava = new FibonacciMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/PerfectSquaresMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/PerfectSquaresMain.scala new file mode 100644 index 00000000..cde3520c --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/PerfectSquaresMain.scala @@ -0,0 +1,42 @@ +package org.combinators.boilerplate.integer + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.integer.PerfectSquares + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +trait PerfectSquaresApp { + val tests = Seq( + new TestExample("ps1", LiteralInt(13), LiteralInt(2), new UnitExpression), // 9 + 4 + new TestExample("ps2", LiteralInt(14), LiteralInt(3), new UnitExpression), // 9 + 4 + 1 + new TestExample("ps3", LiteralInt(15), LiteralInt(4), new UnitExpression), // 9 + 4 + 1 + 1 + new TestExample("ps4", LiteralInt(16), LiteralInt(1), new UnitExpression), // 16 + ) + val model: EnhancedModel = new PerfectSquares().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class PerfectSquaresMainJava extends EnhancedDPMainJava with PerfectSquaresApp { + override def constructApp(): EnhancedDPMainJava = new PerfectSquaresMainJava() +} +class PerfectSquaresMainScala extends EnhancedDPMainScala with PerfectSquaresApp { + override def constructApp(): EnhancedDPMainScala = new PerfectSquaresMainScala() +} + +// need objects to be able to execute as IOApp +object PerfectSquaresScalaToDiskMain extends EnhancedDPMainScala with PerfectSquaresApp { + override def constructApp(): EnhancedDPMainScala = new PerfectSquaresMainScala() +} +object PerfectSquaresJavaToDiskMain extends EnhancedDPMainJava with PerfectSquaresApp { + override def constructApp(): EnhancedDPMainJava = new PerfectSquaresMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/TribonacciMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/TribonacciMain.scala new file mode 100644 index 00000000..1e085a87 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/integer/TribonacciMain.scala @@ -0,0 +1,36 @@ +package org.combinators.boilerplate.integer + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.integer.Tribonacci + +trait TribonacciApp { + val tests = Seq( + new TestExample("trib0", LiteralInt(0), LiteralInt(0), new UnitExpression), + new TestExample("trib1", LiteralInt(1), LiteralInt(1), new UnitExpression), + new TestExample("trib2", LiteralInt(2), LiteralInt(1), new UnitExpression), + new TestExample("trib3", LiteralInt(3), LiteralInt(2), new UnitExpression), + new TestExample("trib4", LiteralInt(4), LiteralInt(4), new UnitExpression), + new TestExample("trib5", LiteralInt(5), LiteralInt(7), new UnitExpression), + ) + + val model: EnhancedModel = new Tribonacci().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class TribonacciMainJava extends EnhancedDPMainJava with TribonacciApp { + override def constructApp(): EnhancedDPMainJava = new TribonacciMainJava() +} +class TribonacciMainScala extends EnhancedDPMainScala with TribonacciApp { + override def constructApp(): EnhancedDPMainScala = new TribonacciMainScala() +} + +// need objects to be able to execute as IOApp +object TribonacciScalaToDiskMain extends EnhancedDPMainScala with TribonacciApp { + override def constructApp(): EnhancedDPMainScala = new TribonacciMainScala() +} +object TribonacciJavaToDiskMain extends EnhancedDPMainJava with TribonacciApp { + override def constructApp(): EnhancedDPMainJava = new TribonacciMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/JumpGameMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/JumpGameMain.scala new file mode 100644 index 00000000..3989546a --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/JumpGameMain.scala @@ -0,0 +1,36 @@ +package org.combinators.boilerplate.oneSequence + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.JumpGame + +/** + * All that is needed here is the set of test cases that you need. + */ +trait JumpGameApp { + + val tests = Seq( + new TestExample("ts1", LiteralArray(Array(1, 100, 1, 1, 1, 100, 1, 1, 100, 1)), LiteralInt(6), new UnitExpression), + new TestExample("ts2", LiteralArray(Array(10, 15, 20)), LiteralInt(15), new UnitExpression), + ) + + val model: EnhancedModel = new JumpGame().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class JumpGameMainJava extends EnhancedDPMainJava with JumpGameApp { + override def constructApp(): EnhancedDPMainJava = new JumpGameMainJava() +} +class JumpGameMainScala extends EnhancedDPMainScala with JumpGameApp { + override def constructApp(): EnhancedDPMainScala = new JumpGameMainScala() +} + +// need objects to be able to execute as IOApp +object JumpGameScalaToDiskMain extends EnhancedDPMainScala with JumpGameApp { + override def constructApp(): EnhancedDPMainScala = new JumpGameMainScala() +} +object JumpGameJavaToDiskMain extends EnhancedDPMainJava with JumpGameApp { + override def constructApp(): EnhancedDPMainJava = new JumpGameMainJava() +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/LongestIncreasingSubsequenceMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/LongestIncreasingSubsequenceMain.scala new file mode 100644 index 00000000..071a98ef --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/LongestIncreasingSubsequenceMain.scala @@ -0,0 +1,45 @@ +package org.combinators.boilerplate.oneSequence + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.LongestIncreasingSubsequence + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +trait LongestIncreasingSubsequenceApp { + + val tests = Seq( + /** https://en.wikipedia.org/wiki/Longest_increasing_subsequence */ + new TestExample("lis1", LiteralArray(Array(0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15)), LiteralInt(6), new UnitExpression), + + /** https://www.geeksforgeeks.org/dsa/longest-increasing-subsequence-dp-3/ */ + new TestExample("lis2", LiteralArray(Array(3, 10, 2, 1, 20)), LiteralInt(3), new UnitExpression) + ) + + val model: EnhancedModel = new LongestIncreasingSubsequence().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class LongestIncreasingSubsequenceMainJava extends EnhancedDPMainJava with LongestIncreasingSubsequenceApp { + override def constructApp(): EnhancedDPMainJava = new LongestIncreasingSubsequenceMainJava() +} +class LongestIncreasingSubsequenceMainScala extends EnhancedDPMainScala with LongestIncreasingSubsequenceApp { + override def constructApp(): EnhancedDPMainScala = new LongestIncreasingSubsequenceMainScala() +} + +// need objects to be able to execute as IOApp +object LongestIncreasingSubsequenceScalaToDiskMain extends EnhancedDPMainScala with LongestIncreasingSubsequenceApp { + override def constructApp(): EnhancedDPMainScala = new LongestIncreasingSubsequenceMainScala() +} +object LongestIncreasingSubsequenceJavaToDiskMain extends EnhancedDPMainJava with LongestIncreasingSubsequenceApp { + override def constructApp(): EnhancedDPMainJava = new LongestIncreasingSubsequenceMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/LongestValidParenthesesMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/LongestValidParenthesesMain.scala new file mode 100644 index 00000000..3fc5cd0b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/LongestValidParenthesesMain.scala @@ -0,0 +1,45 @@ +package org.combinators.boilerplate.oneSequence + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.LongestValidParentheses + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +trait LongestValidParenthesesApp { + + val tests = Seq( + /** https://leetcode.com/problems/longest-valid-parentheses */ + new TestExample("lvp1", LiteralString(")()())"), LiteralInt(4), new UnitExpression), + + /** https://leetcode.com/problems/longest-valid-parentheses/solutions/14133/my-dp-on-solution-without-using-stack-by-nsyp/ */ + new TestExample("lvp2", LiteralString("()(())"), LiteralInt(6), new UnitExpression), + ) + + val model: EnhancedModel = new LongestValidParentheses().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class LongestValidParenthesesMainJava extends EnhancedDPMainJava with LongestValidParenthesesApp { + override def constructApp(): EnhancedDPMainJava = new LongestValidParenthesesMainJava() +} +class LongestValidParenthesesMainScala extends EnhancedDPMainScala with LongestValidParenthesesApp { + override def constructApp(): EnhancedDPMainScala = new LongestValidParenthesesMainScala() +} + +// need objects to be able to execute as IOApp +object LongestValidParenthesesScalaToDiskMain extends EnhancedDPMainScala with LongestValidParenthesesApp { + override def constructApp(): EnhancedDPMainScala = new LongestValidParenthesesMainScala() +} +object LongestValidParenthesesJavaToDiskMain extends EnhancedDPMainJava with LongestValidParenthesesApp { + override def constructApp(): EnhancedDPMainJava = new LongestValidParenthesesMainJava() +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MatrixChainMultiplicationMainBottomUp.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MatrixChainMultiplicationMainBottomUp.scala new file mode 100644 index 00000000..fe2a480c --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MatrixChainMultiplicationMainBottomUp.scala @@ -0,0 +1,42 @@ +package org.combinators.boilerplate.oneSequence + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.TestExample +import org.combinators.dp.original.BottomUp +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.MatrixChainMultiplicationBU + +/** + * All that is needed here is the set of test cases that you need. + */ +trait MatrixChainMultiplicationMainBottomUpApp { + + val tests = Seq( + new TestExample("mm1", LiteralArray(Array(40, 20, 30, 10, 30)), LiteralInt(26000), new UnitExpression), // + new TestExample("mm2", LiteralArray(Array(2, 1, 3, 4)), LiteralInt(20), new UnitExpression), // https://www.geeksforgeeks.org/problems/matrix-chain-multiplication0303/1 + new TestExample("mm3", LiteralArray(Array(10, 30, 5, 60)), LiteralInt(4500), new UnitExpression), // ttps://en.wikipedia.org/wiki/Matrix_chain_multiplication + ) + + val model: EnhancedModel = new MatrixChainMultiplicationBU().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class MatrixChainMultiplicationBottomUpMainJava extends EnhancedDPMainJava with MatrixChainMultiplicationMainBottomUpApp { + override def constructApp(): EnhancedDPMainJava = new MatrixChainMultiplicationBottomUpMainJava() +} +class MatrixChainMultiplicationBottomUpMainScala extends EnhancedDPMainScala with MatrixChainMultiplicationMainBottomUpApp { + override def constructApp(): EnhancedDPMainScala = new MatrixChainMultiplicationBottomUpMainScala() +} + +// need objects to be able to execute as IOApp +object MatrixChainMultiplicationBottomUpScalaToDiskMain extends EnhancedDPMainScala with MatrixChainMultiplicationMainBottomUpApp { + override def constructApp(): EnhancedDPMainScala = new MatrixChainMultiplicationBottomUpMainScala() +} +object MatrixChainMultiplicationBottomUpJavaToDiskMain extends EnhancedDPMainJava with MatrixChainMultiplicationMainBottomUpApp { + override def constructApp(): EnhancedDPMainJava = new MatrixChainMultiplicationBottomUpMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MatrixChainMultiplicationMainTopDown.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MatrixChainMultiplicationMainTopDown.scala new file mode 100644 index 00000000..e2d4116d --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MatrixChainMultiplicationMainTopDown.scala @@ -0,0 +1,42 @@ +package org.combinators.boilerplate.oneSequence + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.TestExample +import org.combinators.dp.original.TopDown +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.MatrixChainMultiplicationTD + +/** + * All that is needed here is the set of test cases that you need. + */ +trait MatrixChainMultiplicationMainTopDownApp { + + val tests = Seq( + new TestExample("mm1", LiteralArray(Array(40, 20, 30, 10, 30)), LiteralInt(26000), new UnitExpression), // + new TestExample("mm2", LiteralArray(Array(2, 1, 3, 4)), LiteralInt(20), new UnitExpression), // https://www.geeksforgeeks.org/problems/matrix-chain-multiplication0303/1 + new TestExample("mm3", LiteralArray(Array(10, 30, 5, 60)), LiteralInt(4500), new UnitExpression), // ttps://en.wikipedia.org/wiki/Matrix_chain_multiplication + ) + + val model: EnhancedModel = new MatrixChainMultiplicationTD().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class MatrixChainMultiplicationTopDownMainJava extends EnhancedDPMainJava with MatrixChainMultiplicationMainTopDownApp { + override def constructApp(): EnhancedDPMainJava = new MatrixChainMultiplicationTopDownMainJava() +} +class MatrixChainMultiplicationTopDownMainScala extends EnhancedDPMainScala with MatrixChainMultiplicationMainTopDownApp { + override def constructApp(): EnhancedDPMainScala = new MatrixChainMultiplicationTopDownMainScala() +} + +// need objects to be able to execute as IOApp +object MatrixChainMultiplicationTopDownScalaToDiskMain extends EnhancedDPMainScala with MatrixChainMultiplicationMainTopDownApp { + override def constructApp(): EnhancedDPMainScala = new MatrixChainMultiplicationTopDownMainScala() +} +object MatrixChainMultiplicationTopDownJavaToDiskMain extends EnhancedDPMainJava with MatrixChainMultiplicationMainTopDownApp { + override def constructApp(): EnhancedDPMainJava = new MatrixChainMultiplicationTopDownMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MaximalIndependentSetPathMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MaximalIndependentSetPathMain.scala new file mode 100644 index 00000000..a5096079 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MaximalIndependentSetPathMain.scala @@ -0,0 +1,42 @@ +package org.combinators.boilerplate.oneSequence + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.MaximalIndependentSetPath + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +trait MaximalIndependentSetPathApp { + + val tests = Seq( + // https://canvas.wpi.edu/courses/79353 + new TestExample("sp1", LiteralArray(Array(12,11,13,15)), LiteralInt(27), new UnitExpression), + new TestExample("sp2", LiteralArray(Array(2,1000,3,1)), LiteralInt(1001), new UnitExpression), + ) + val model: EnhancedModel = new MaximalIndependentSetPath().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class MaximalIndependentSetPathMainJava extends EnhancedDPMainJava with MaximalIndependentSetPathApp { + override def constructApp(): EnhancedDPMainJava = new MaximalIndependentSetPathMainJava() +} +class MaximalIndependentSetPathMainScala extends EnhancedDPMainScala with MaximalIndependentSetPathApp { + override def constructApp(): EnhancedDPMainScala = new MaximalIndependentSetPathMainScala() +} + +// need objects to be able to execute as IOApp +object MaximalIndependentSetPathScalaToDiskMain extends EnhancedDPMainScala with MaximalIndependentSetPathApp { + override def constructApp(): EnhancedDPMainScala = new MaximalIndependentSetPathMainScala() +} +object MaximalIndependentSetPathJavaToDiskMain extends EnhancedDPMainJava with MaximalIndependentSetPathApp { + override def constructApp(): EnhancedDPMainJava = new MaximalIndependentSetPathMainJava() +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MinCostClimbingStairMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MinCostClimbingStairMain.scala new file mode 100644 index 00000000..01396d48 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/oneSequence/MinCostClimbingStairMain.scala @@ -0,0 +1,36 @@ +package org.combinators.boilerplate.oneSequence + +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.oneSequence.MinCostClimbingStair + +/** + * All that is needed here is the set of test cases that you need. + */ +trait MinCostClimbingStairApp { + + val tests = Seq( + new TestExample("ts1", LiteralArray(Array(1,100,1,1,1,100,1,1,100,1)), LiteralInt(6), new UnitExpression), + new TestExample("ts2", LiteralArray(Array(10,15,20)), LiteralInt(15), new UnitExpression), + ) + + val model: EnhancedModel = new MinCostClimbingStair().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class MinCostClimbingStairMainJava extends EnhancedDPMainJava with MinCostClimbingStairApp { + override def constructApp(): EnhancedDPMainJava = new MinCostClimbingStairMainJava() +} +class MinCostClimbingStairMainScala extends EnhancedDPMainScala with MinCostClimbingStairApp { + override def constructApp(): EnhancedDPMainScala = new MinCostClimbingStairMainScala() +} + +// need objects to be able to execute as IOApp +object MinCostClimbingStairScalaToDiskMain extends EnhancedDPMainScala with MinCostClimbingStairApp { + override def constructApp(): EnhancedDPMainScala = new MinCostClimbingStairMainScala() +} +object MinCostClimbingStairJavaToDiskMain extends EnhancedDPMainJava with MinCostClimbingStairApp { + override def constructApp(): EnhancedDPMainJava = new MinCostClimbingStairMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/strings/InterleaveStringsMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/strings/InterleaveStringsMain.scala new file mode 100644 index 00000000..db36d8cd --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/strings/InterleaveStringsMain.scala @@ -0,0 +1,42 @@ +package org.combinators.boilerplate.strings + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.strings.InterleaveStrings + +/** + * All that is needed here is the set of test cases that you need. + */ +trait InterleaveStringsApp { + + val tests = Seq( + new TestExample("ils1", LiteralTuple(LiteralString("aabcc"), LiteralString("dbbca"), LiteralString("aadbbcbcac")), LiteralBoolean(true), new UnitExpression), + new TestExample("ils1", LiteralTuple(LiteralString("aab"), LiteralString("axy"), LiteralString("aaxaby")), LiteralBoolean(true), new UnitExpression), + new TestExample("ils1", LiteralTuple(LiteralString("aab"), LiteralString("axy"), LiteralString("abaaxy")), LiteralBoolean(false), new UnitExpression), + ) + + val model: EnhancedModel = new InterleaveStrings().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class InterleaveStringsMainJava extends EnhancedDPMainJava with InterleaveStringsApp { + override def constructApp(): EnhancedDPMainJava = new InterleaveStringsMainJava() +} +class InterleaveStringsMainScala extends EnhancedDPMainScala with InterleaveStringsApp { + override def constructApp(): EnhancedDPMainScala = new InterleaveStringsMainScala() +} + +// need objects to be able to execute as IOApp +object InterleaveStringsScalaToDiskMain extends EnhancedDPMainScala with InterleaveStringsApp { + override def constructApp(): EnhancedDPMainScala = new InterleaveStringsMainScala() +} +object InterleaveStringsJavaToDiskMain extends EnhancedDPMainJava with InterleaveStringsApp { + override def constructApp(): EnhancedDPMainJava = new InterleaveStringsMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/strings/ThreeStringLCSMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/strings/ThreeStringLCSMain.scala new file mode 100644 index 00000000..2b9e1e18 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/strings/ThreeStringLCSMain.scala @@ -0,0 +1,42 @@ +package org.combinators.boilerplate.strings + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.* +import org.combinators.models.enhancedModels.strings.ThreeStringLCS + +/** + * All that is needed here is the set of test cases that you need. + */ +trait ThreeStringsLCSApp { + + val tests = Seq( + new TestExample("ts1", LiteralTuple(LiteralString("AGGT12"), LiteralString("12TXAYB"), LiteralString("12XBA")), LiteralInt(2), new UnitExpression), + new TestExample("ts2", LiteralTuple(LiteralString("geeks"), LiteralString("geeksfor"), LiteralString("geeksforgeeks")), LiteralInt(5), new UnitExpression), + new TestExample("ts3", LiteralTuple(LiteralString("abcd1e2"), LiteralString("bc12ea"), LiteralString("bd1ea")), LiteralInt(3), new UnitExpression), + ) + + val model: EnhancedModel = new ThreeStringLCS().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class ThreeStringsLCSMainJava extends EnhancedDPMainJava with ThreeStringsLCSApp { + override def constructApp(): EnhancedDPMainJava = new ThreeStringsLCSMainJava() +} +class ThreeStringsLCSMainScala extends EnhancedDPMainScala with ThreeStringsLCSApp { + override def constructApp(): EnhancedDPMainScala = new ThreeStringsLCSMainScala() +} + +// need objects to be able to execute as IOApp +object ThreeStringsLCSScalaToDiskMain extends EnhancedDPMainScala with ThreeStringsLCSApp { + override def constructApp(): EnhancedDPMainScala = new ThreeStringsLCSMainScala() +} +object ThreeStringsLCSJavaToDiskMain extends EnhancedDPMainJava with ThreeStringsLCSApp { + override def constructApp(): EnhancedDPMainJava = new ThreeStringsLCSMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/DistinctSubsequencesMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/DistinctSubsequencesMain.scala new file mode 100644 index 00000000..3b7425d7 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/DistinctSubsequencesMain.scala @@ -0,0 +1,32 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.DistinctSubsequences + +trait DistinctSubsequencesApp { + val tests = Seq( + new TestExample("ds1", LiteralTuple(LiteralString("rabbbit"), LiteralString("rabbit")), LiteralInt(3), new UnitExpression), + new TestExample("ds2", LiteralTuple(LiteralString("babgbag"), LiteralString("bag")), LiteralInt(5), new UnitExpression), + ) + + val model: EnhancedModel = new DistinctSubsequences().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class DistinctSubsequencesMainJava extends EnhancedDPMainJava with DistinctSubsequencesApp { + override def constructApp(): EnhancedDPMainJava = new DistinctSubsequencesMainJava() +} +class DistinctSubsequencesMainScala extends EnhancedDPMainScala with DistinctSubsequencesApp { + override def constructApp(): EnhancedDPMainScala = new DistinctSubsequencesMainScala() +} + +// need objects to be able to execute as IOApp +object DistinctSubsequencesScalaToDiskMain extends EnhancedDPMainScala with DistinctSubsequencesApp { + override def constructApp(): EnhancedDPMainScala = new DistinctSubsequencesMainScala() +} +object DistinctSubsequencesJavaToDiskMain extends EnhancedDPMainJava with DistinctSubsequencesApp { + override def constructApp(): EnhancedDPMainJava = new DistinctSubsequencesMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/LongestCommonSubsequenceMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/LongestCommonSubsequenceMain.scala new file mode 100644 index 00000000..e3ea0598 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/LongestCommonSubsequenceMain.scala @@ -0,0 +1,31 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.LongestCommonSubsequence + +trait LongestCommonSubsequenceApp { + val tests = Seq( + new TestExample("lcs1", LiteralTuple(LiteralString("abc"), LiteralString("ace")), LiteralInt(2), new UnitExpression), + ) + + val model: EnhancedModel = new LongestCommonSubsequence().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class LongestCommonSubsequenceMainJava extends EnhancedDPMainJava with LongestCommonSubsequenceApp { + override def constructApp(): EnhancedDPMainJava = new LongestCommonSubsequenceMainJava() +} +class LongestCommonSubsequenceMainScala extends EnhancedDPMainScala with LongestCommonSubsequenceApp { + override def constructApp(): EnhancedDPMainScala = new LongestCommonSubsequenceMainScala() +} + +// need objects to be able to execute as IOApp +object LongestCommonSubsequenceScalaToDiskMain extends EnhancedDPMainScala with LongestCommonSubsequenceApp { + override def constructApp(): EnhancedDPMainScala = new LongestCommonSubsequenceMainScala() +} +object LongestCommonSubsequenceJavaToDiskMain extends EnhancedDPMainJava with LongestCommonSubsequenceApp { + override def constructApp(): EnhancedDPMainJava = new LongestCommonSubsequenceMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/NeedlemanWunschMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/NeedlemanWunschMainJava.scala new file mode 100644 index 00000000..3110ab88 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/NeedlemanWunschMainJava.scala @@ -0,0 +1,101 @@ +package org.combinators.boilerplate.twoSequences + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.dp.TestExample +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.{NeedlemanWunschSequenceAlignment, WordBreak} + +import java.nio.file.{Path, Paths} + +// needs custom-support code, because the test case has unusual structure. +case class NeedlemanWunschSequenceInputType() extends ArgumentType +class NeedlemanWunschSequenceInput(val string1:String, val string2:String, val matchBonus:Int, val mismatchPenalty:Int, val gapPenalty:Int) extends LiteralExpression { + def tpe:ArgumentType = NeedlemanWunschSequenceInputType() +} + +class NeedlemanWunschMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = NeedlemanWunschSequenceAlignmentProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.ooParadigm, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.mapsInMethod, ???, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + // subclasses will provide tests and model + val tests = Seq( + new TestExample("nws1", new NeedlemanWunschSequenceInput("abc", "ace", +2, -1, -2), LiteralInt(0), new UnitExpression), + new TestExample("nws2", new NeedlemanWunschSequenceInput("CTCGCAGC", "CATTCAC", +10, -2, -5), LiteralInt(33), new UnitExpression), + ) + + val model: EnhancedModel = new NeedlemanWunschSequenceAlignment().model + + def filesToGenerate(option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, tests, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, option) + } yield ExitCode.Success + } +} + +object NeedlemanWunschDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp", "needlemanWunsch") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new NeedlemanWunschMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, bottomUp) + } yield result + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/NeedlemanWunschSequenceAlignmentProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/NeedlemanWunschSequenceAlignmentProvider.scala new file mode 100644 index 00000000..79ba020e --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/NeedlemanWunschSequenceAlignmentProvider.scala @@ -0,0 +1,169 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, Maps, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.models.{EnhancedModel, LiteralBoolean, LiteralExpression, LiteralInt, LiteralString} +import org.combinators.dp.enhanced.{BottomUpStrategy, EnhancedDPProvider, EnhancedUtility, TopDownStrategy} +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait NeedlemanWunschSequenceAlignmentProvider extends EnhancedDPProvider with EnhancedUtility with TopDownStrategy with BottomUpStrategy { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val maps: Maps.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + // if not memo, then this will be defined and added + lazy val resultVarName = names.mangle("result") + + import paradigm._ + import syntax._ + import ooParadigm._ + + // expand as necessary + def literalMapping(litExpr:LiteralExpression): Generator[MethodBodyContext, Expression] = { + + // only SINGLE values can go here + litExpr match { + case lit: LiteralInt => paradigm.methodBodyCapabilities.reify(TypeRep.Int, lit.literal) + case bool: LiteralBoolean => paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, bool.literal) + case str: LiteralString => paradigm.methodBodyCapabilities.reify(TypeRep.String, str.literal) + + case _ => ??? // error in all other circumstances + } + } + + def needlemanWunschTests(implementation:String, tests: Seq[TestExample]): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + for { + assert_statements <- forEach(tests) { test => + + val output = test.answer match { + case lit:LiteralInt => lit.literal + case _ => ??? + } + + // Arrays have to be handled specially, I'm afraid + val values = test.inputType match { + case nw:NeedlemanWunschSequenceInput => (nw.string1, nw.string2, nw.matchBonus, nw.mismatchPenalty, nw.gapPenalty) + case _ => ??? + } + + for { + solType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + s1 <- paradigm.methodBodyCapabilities.reify(TypeRep.String, values._1) + s2 <- paradigm.methodBodyCapabilities.reify(TypeRep.String, values._2) + matchBonus <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, values._3) + mismatchPenalty <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, values._4) + gapPenalty <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, values._5) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(s1, s2, matchBonus, mismatchPenalty, gapPenalty)) + + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + sol_actual <- apply(computeMethod, Seq.empty) + sol_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, output) + theType <- toTargetLanguageType(TypeRep.Int) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(theType, sol_actual, sol_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + def makeTestCase(clazzName:String, tests:Seq[TestExample]): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(needlemanWunschTests(clazzName, tests), names.mangle(clazzName)) + } yield () + } + + /** Trying out some new capabiltiies */ + def implement(model: EnhancedModel, tests:Seq[TestExample], option:GenerationOption): Generator[ProjectContext, Unit] = { + + // handle Top/Bottom and properly set memo when TD + var isTopDown = false + var useMemo = false + option match { + case td:TopDown => + useMemo = td.memo + isTopDown = true + + case _:BottomUp => + isTopDown = false + } + + for { + // The code below generates the actual class, based on model.problem + _ <- if (isTopDown) { + make_top_down(useMemo, model) + } else { + make_bottom_up(model) + } + + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(names.mangle("Test" + model.problem), makeTestCase(model.problem, tests)) + ) + } yield () + } +} + +object NeedlemanWunschSequenceAlignmentProvider { + type WithParadigm[P <: AnyParadigm] = NeedlemanWunschSequenceAlignmentProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + maps: Maps.WithBase[base.MethodBodyContext, base.type], + mapsInConst: Maps.WithBase[oo.ConstructorContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): NeedlemanWunschSequenceAlignmentProvider.WithParadigm[base.type] = + new NeedlemanWunschSequenceAlignmentProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val maps: Maps.WithBase[base.MethodBodyContext, paradigm.type] = maps + override val mapsInConstructors: Maps.WithBase[ooParadigm.ConstructorContext, paradigm.type] = mapsInConst + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/ShortestCommonSupersequenceMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/ShortestCommonSupersequenceMain.scala new file mode 100644 index 00000000..ba9b0dc5 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/ShortestCommonSupersequenceMain.scala @@ -0,0 +1,35 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.ShortestCommonSupersequence + +trait ShortestCommonSupersequenceApp { + val tests = Seq( + new TestExample("scs1", LiteralTuple(LiteralString("abac"), LiteralString("cab")), LiteralInt(5), new UnitExpression), + new TestExample("scs2", LiteralTuple(LiteralString("abc"), LiteralString("ac")), LiteralInt(4), new UnitExpression), + new TestExample("scs3", LiteralTuple(LiteralString("abc"), LiteralString("abc")), LiteralInt(3), new UnitExpression), + new TestExample("scs4", LiteralTuple(LiteralString(""), LiteralString("abc")), LiteralInt(3), new UnitExpression), + new TestExample("scs5", LiteralTuple(LiteralString("abc"), LiteralString("")), LiteralInt(3), new UnitExpression), + ) + + val model: EnhancedModel = new ShortestCommonSupersequence().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class ShortestCommonSupersequenceMainJava extends EnhancedDPMainJava with ShortestCommonSupersequenceApp { + override def constructApp(): EnhancedDPMainJava = new ShortestCommonSupersequenceMainJava() +} +class ShortestCommonSupersequenceMainScala extends EnhancedDPMainScala with ShortestCommonSupersequenceApp { + override def constructApp(): EnhancedDPMainScala = new ShortestCommonSupersequenceMainScala() +} + +// need objects to be able to execute as IOApp +object ShortestCommonSupersequenceScalaToDiskMain extends EnhancedDPMainScala with ShortestCommonSupersequenceApp { + override def constructApp(): EnhancedDPMainScala = new ShortestCommonSupersequenceMainScala() +} +object ShortestCommonSupersequenceJavaToDiskMain extends EnhancedDPMainJava with ShortestCommonSupersequenceApp { + override def constructApp(): EnhancedDPMainJava = new ShortestCommonSupersequenceMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/UncrossedLinesMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/UncrossedLinesMain.scala new file mode 100644 index 00000000..9c9238ee --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/UncrossedLinesMain.scala @@ -0,0 +1,31 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.UncrossedLines + +trait UncrossedLinesApp { + val tests = Seq( + new TestExample("ul1", LiteralTuple(LiteralArray(Array(1, 4, 2)), LiteralArray(Array(1, 2, 4))), LiteralInt(2), new UnitExpression) + ) + + val model: EnhancedModel = new UncrossedLines().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class UncrossedLinesMainJava extends EnhancedDPMainJava with UncrossedLinesApp { + override def constructApp(): EnhancedDPMainJava = new UncrossedLinesMainJava() +} +class UncrossedLinesMainScala extends EnhancedDPMainScala with UncrossedLinesApp { + override def constructApp(): EnhancedDPMainScala = new UncrossedLinesMainScala() +} + +// need objects to be able to execute as IOApp +object UncrossedLinesScalaToDiskMain extends EnhancedDPMainScala with UncrossedLinesApp { + override def constructApp(): EnhancedDPMainScala = new UncrossedLinesMainScala() +} +object UncrossedLinesJavaToDiskMain extends EnhancedDPMainJava with UncrossedLinesApp { + override def constructApp(): EnhancedDPMainJava = new UncrossedLinesMainJava() +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WildcardPatternMatchingMain.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WildcardPatternMatchingMain.scala new file mode 100644 index 00000000..ff62cc09 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WildcardPatternMatchingMain.scala @@ -0,0 +1,35 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.dp.enhanced.{EnhancedDPMainJava, EnhancedDPMainScala} +import org.combinators.dp.original.{BottomUp, TopDown} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.WildcardPatternMatching + +trait WildcardPatternMatchingApp { + val tests = Seq( + new TestExample("wpm1", LiteralTuple(LiteralString("a*b*c"), LiteralString("afhuirbfhwnkc")), LiteralBoolean(true), new UnitExpression), + new TestExample("wpm2", LiteralTuple(LiteralString("a?b?c"), LiteralString("a")), LiteralBoolean(false), new UnitExpression), + new TestExample("wpm4", LiteralTuple(LiteralString("adceb"), LiteralString("*a*b")), LiteralBoolean(true), new UnitExpression), + new TestExample("wpm5", LiteralTuple(LiteralString(""), LiteralString("*")), LiteralBoolean(true), new UnitExpression), + new TestExample("wpm6", LiteralTuple(LiteralString(""), LiteralString("")), LiteralBoolean(true), new UnitExpression), + ) + + val model: EnhancedModel = new WildcardPatternMatching().model +} + +// Need these two classes to extend appropriate *MainJava or *MainScala +class WildcardPatternMatchingMainJava extends EnhancedDPMainJava with WildcardPatternMatchingApp { + override def constructApp(): EnhancedDPMainJava = new WildcardPatternMatchingMainJava() +} +class WildcardPatternMatchingMainScala extends EnhancedDPMainScala with WildcardPatternMatchingApp { + override def constructApp(): EnhancedDPMainScala = new WildcardPatternMatchingMainScala() +} + +// need objects to be able to execute as IOApp +object WildcardPatternMatchingScalaToDiskMain extends EnhancedDPMainScala with WildcardPatternMatchingApp { + override def constructApp(): EnhancedDPMainScala = new WildcardPatternMatchingMainScala() +} +object WildcardPatternMatchingJavaToDiskMain extends EnhancedDPMainJava with WildcardPatternMatchingApp { + override def constructApp(): EnhancedDPMainJava = new WildcardPatternMatchingMainJava() +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WordBreakMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WordBreakMainJava.scala new file mode 100644 index 00000000..baab850a --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WordBreakMainJava.scala @@ -0,0 +1,102 @@ +package org.combinators.boilerplate.twoSequences + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.dp.TestExample +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.boilerplate.twoSequences.WordBreakProvider +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, Syntax, Unboxed} +import org.combinators.models.* +import org.combinators.models.enhancedModels.twoSequences.WordBreak + +import java.nio.file.{Path, Paths} + +// needs custom-support code, because the test case has unusual structure. +case class WordBreakInputType() extends ArgumentType +class WordBreakInput(val s:String, val dictionary:Array[String]) extends LiteralExpression { + def tpe:ArgumentType = WordBreakInputType() +} + +class WordBreakMainJava { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = WordBreakProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.mapsInMethod, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.ooParadigm, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + // subclasses will provide tests and model + val tests = Seq( + new TestExample("wb1", new WordBreakInput("catsanddog", Array("cats","dog","sand","and","cat")), LiteralBoolean(false), new UnitExpression), + new TestExample("wb2", new WordBreakInput("leetcode", Array("leet","code")), LiteralBoolean(true), new UnitExpression) + ) + + val model: EnhancedModel = new WordBreak().model + + def filesToGenerate(option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, tests, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, option) + } yield ExitCode.Success + } +} + +object WordBreakDirectToDiskMain extends IOApp { + val targetDirectory:Path = Paths.get("target", "dp", "wordBreak") + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new WordBreakMainJava() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(targetDirectory, bottomUp) + } yield result + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WordBreakProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WordBreakProvider.scala new file mode 100644 index 00000000..ed25b2db --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/boilerplate/twoSequences/WordBreakProvider.scala @@ -0,0 +1,164 @@ +package org.combinators.boilerplate.twoSequences + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, Maps, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.models.{EnhancedModel, LiteralBoolean, LiteralExpression, LiteralInt, LiteralString} +import org.combinators.dp.enhanced.{BottomUpStrategy, EnhancedDPProvider, EnhancedUtility, TopDownStrategy} +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait WordBreakProvider extends EnhancedDPProvider with EnhancedUtility with TopDownStrategy with BottomUpStrategy { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext ,paradigm.type] + val maps: Maps.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + // if not memo, then this will be defined and added + lazy val resultVarName = names.mangle("result") + + import paradigm._ + import syntax._ + + // expand as necessary + def literalMapping(litExpr:LiteralExpression): Generator[MethodBodyContext, Expression] = { + + // only SINGLE values can go here + litExpr match { + case lit: LiteralInt => paradigm.methodBodyCapabilities.reify(TypeRep.Int, lit.literal) + case bool: LiteralBoolean => paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, bool.literal) + case str: LiteralString => paradigm.methodBodyCapabilities.reify(TypeRep.String, str.literal) + + case _ => ??? // error in all other circumstances + } + } + + def wordBreakTests(implementation:String, tests: Seq[TestExample]): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + for { + assert_statements <- forEach(tests) { test => + + val output = test.answer match { + case lit:LiteralBoolean => lit.literal + case _ => ??? + } + + // Arrays have to be handled specially, I'm afraid + val values = test.inputType match { + case wb:WordBreakInput => (wb.s, wb.dictionary) + case _ => ??? + } + + for { + solType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + s <- paradigm.methodBodyCapabilities.reify(TypeRep.String, values._1) + dict <- create_string_array(values._2) + + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(s, dict)) + + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + + sol_actual <- apply(computeMethod, Seq.empty) + sol_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, output) + theType <- toTargetLanguageType(TypeRep.Boolean) + asserteq_fib <- asserts.assertionCapabilities.assertEquals(theType, sol_actual, sol_value) + + } yield asserteq_fib + } + } yield assert_statements + } + + def makeTestCase(clazzName:String, tests:Seq[TestExample]): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(wordBreakTests(clazzName, tests), names.mangle(clazzName)) + } yield () + } + + /** Trying out some new capabiltiies */ + def implement(model: EnhancedModel, tests:Seq[TestExample], option:GenerationOption): Generator[ProjectContext, Unit] = { + + // handle Top/Bottom and properly set memo when TD + var isTopDown = false + var useMemo = false + option match { + case td:TopDown => + useMemo = td.memo + isTopDown = true + + case _:BottomUp => + isTopDown = false + } + + for { + // The code below generates the actual class, based on model.problem + _ <- if (isTopDown) { + make_top_down(useMemo, model) + } else { + make_bottom_up(model) + } + + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(names.mangle("Test" + model.problem), makeTestCase(model.problem, tests)) + ) + } yield () + } +} + +object WordBreakProvider { + type WithParadigm[P <: AnyParadigm] = WordBreakProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + maps: Maps.WithBase[base.MethodBodyContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): WordBreakProvider.WithParadigm[base.type] = + new WordBreakProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val maps: Maps.WithBase[base.MethodBodyContext, paradigm.type] = maps + override val mapsInConstructors = ??? + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/TestExample.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/TestExample.scala new file mode 100644 index 00000000..c6d7d96c --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/TestExample.scala @@ -0,0 +1,7 @@ +package org.combinators.dp + +import org.combinators.models.LiteralExpression + +// VAST majority will have answer as an Integer, but sometimes it is a String or Boolean +class TestExample(val name:String, val inputType:LiteralExpression, val answer:LiteralExpression, val solutionType:LiteralExpression) + diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/BottomUpStrategy.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/BottomUpStrategy.scala new file mode 100644 index 00000000..f0a89933 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/BottomUpStrategy.scala @@ -0,0 +1,441 @@ +package org.combinators.dp.enhanced + +import org.combinators.cogen.TypeRep +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi._ +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.NameProvider +import org.combinators.dp.original.Utility +import org.combinators.models._ + +/** + * Concepts necessary to realize top-down solutions + */ + +trait BottomUpStrategy extends Utility with EnhancedUtility { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val iName = names.mangle("i") + lazy val nName = names.mangle("n") + lazy val dpName = names.mangle("dp") + + // will need to be expanded to depth-10 or something + def arTypes(model: EnhancedModel): TypeRep = { + + val params = model.mode match { + case ut:UpperTriangle => ut.params + case _ => model.solution.order + } + + // was model.input.length + model.subproblemType match { + case _:IntegerType => constructedArrayType(params.length, TypeRep.Int) + case _:CharType => constructedArrayType(params.length, TypeRep.Char) + case _:BooleanType => constructedArrayType(params.length, TypeRep.Boolean) + + case _ => ??? + } + } + + def make_bottom_up_compute_method_recursive(model:EnhancedModel, order:Seq[String]): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + case class TraversalInformation( + statements:Seq[Statement], + highs:Seq[Expression], + symbols:Map[String,Expression], + computedDpAccess:Expression, + dpAccess:Expression) + + // return (Seq[statement] containing whileloop(s) and then seq of high vars, to be used by instantiation + def traverse_inwards(level:Int, dpAccess:Expression, symbolTable:Map[String, Expression]): Generator[MethodBodyContext, TraversalInformation] = { + if (level == order.length) { + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + dp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + + // This handles more advances cases when there are mappers + real_access <- order.foldLeft(ooParadigm.methodBodyCapabilities.getMember(self, dpName)) ( (state, level_var) => + for { + current_dp <- state + next_expr <- explore(model.find_map(level_var), bottomUp=Some(dp), symbolTable=symbolTable, memoize=false) + dp_next <- array.arrayCapabilities.get(current_dp, Seq(next_expr)) + } yield dp_next + ) + + av <- generate(dp, real_access, model.definition, symbolTable=symbolTable) + } yield TraversalInformation(av, Seq.empty, symbolTable, real_access, dpAccess) + } else { + for { + intType <- toTargetLanguageType(TypeRep.Int) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + self <- ooParadigm.methodBodyCapabilities.selfReference() + dp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + + level_low <- explore(model.find(order(level)).low, bottomUp=Some(dp), symbolTable=symbolTable, memoize=false) + level_high <- explore(model.find(order(level)).high, bottomUp=Some(dp), symbolTable=symbolTable, memoize=false) + level_var <- impParadigm.imperativeCapabilities.declareVar(names.mangle(order(level)), intType, Some(zero)) // in scala-gen, cannot have default vals and this is reasonable + level_map = symbolTable + (order(level) -> level_var) + + expr <- explore(model.find(order(level)), bottomUp=Some(dp), symbolTable=level_map) + dp_next <- array.arrayCapabilities.get(dpAccess, Seq(expr)) + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + traversalInfo <- traverse_inwards(level + 1, dp_next, level_map) + + level_condition <- explore(model.find(order(level)).in_range, bottomUp=Some(dp), symbolTable=level_map, memoize=false) + + // reset counter variable + loop_var_decl <- impParadigm.imperativeCapabilities.assignVar(level_var, level_low) + level_whileLoop <- impParadigm.imperativeCapabilities.whileLoop(level_condition, for { + _ <- addBlockDefinitions(traversalInfo.statements) + + level_var_plusone <- arithmetic.arithmeticCapabilities.add(level_var, one) + incr_inner <- impParadigm.imperativeCapabilities.assignVar(level_var, level_var_plusone) + + _ <- addBlockDefinitions(Seq(incr_inner)) + } yield ()) + } yield TraversalInformation(Seq(loop_var_decl,level_whileLoop), level_high +: traversalInfo.highs, traversalInfo.symbols, traversalInfo.computedDpAccess, traversalInfo.dpAccess) + } + } + + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + theType <- return_type_based_on_model(model) + _ <- setReturnType(theType) + + // cannot seem to do this in Constructor because it insists on using "int" for TypeRep.Int within ConstructorContext which + // seems to be different from Integer which occurs in MethodBodyContext + dp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + + traversalInfo <- traverse_inwards(0, dp, Map.empty) + instantiated <- array.arrayCapabilities.create(theType, traversalInfo.highs, None) // in new situation, only type of element, NOT full [][][] type + assign_stmt <- impParadigm.imperativeCapabilities.assignVar (dp, instantiated) + + _ <- addBlockDefinitions(Seq(assign_stmt)) + _ <- addBlockDefinitions(traversalInfo.statements) + + // when this is a ReturnExpression, essentially dpAccess is ignored since drawn solely from model.answer + // the model would be responsible for choosing computedAccess or dpAccess. for now, leave as future work + choice = traversalInfo.dpAccess + av <- generate(dp, choice, model.answer, symbolTable=traversalInfo.symbols) + _ <- addBlockDefinitions(av) + + } yield None + } + + def report(str:String) : Generator[paradigm.MethodBodyContext, Unit] = { + println(str) + for { + ne77 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -77) + } yield () + } + + def exploreExpr(dp:Expression, defs:DefinitionStatement, symbolTable: Map[String,Expression]) : Generator[paradigm.MethodBodyContext, Expression] = { + defs match { + case es:ExpressionStatement => for { + e <- explore(es.expr, memoize = false, symbolTable = symbolTable, bottomUp=Some(dp)) + } yield e + + case _ => ??? + } + } + + def generate (dp:Expression, dpij:Expression, defn:Definition, symbolTable: Map[String,Expression]) : Generator[paradigm.MethodBodyContext, Seq[Statement]] = { + import paradigm.methodBodyCapabilities._ + import ooParadigm.methodBodyCapabilities._ + import AnyParadigm.syntax._ + + defn match { + case ed: ExpressionDefinition => for { + expr <- explore(ed.expr, symbolTable = symbolTable, bottomUp = Some(dp)) + assigned <- impParadigm.imperativeCapabilities.assignVar(dpij, expr) + } yield Seq(assigned) + + case ed: ReturnExpressionDefinition => for { + expr <- explore(ed.expr, symbolTable = symbolTable, bottomUp = Some(dp)) + assigned <- impParadigm.imperativeCapabilities.returnStmt(expr) + } yield Seq(assigned) + + case ite: IfThenElseDefinition => for { + inner <- explore(ite.condition, symbolTable = symbolTable, bottomUp = Some(dp)) + ifstmt <- impParadigm.imperativeCapabilities.ifThenElse( + // condition of first if + inner + , + // statements for that first if + for { + expr <- exploreExpr(dp, ite.result, symbolTable = symbolTable) + assigned <- impParadigm.imperativeCapabilities.assignVar(dpij, expr) + _ <- addBlockDefinitions(Seq(assigned)) + } yield () + , + // collection of (condition, block) for all remaining cases + Seq.empty + , + // terminating 'else' takes the elseCase and adds it last + Some(for { + stmts <- generate(dp, dpij, ite.elseExpression, symbolTable = symbolTable) + _ <- addBlockDefinitions(stmts) + } yield ()) + ) + } yield Seq(ifstmt) + + case ds: MinRangeDefinition => for { + maxValue <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, scala.Int.MaxValue) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + intType <- toTargetLanguageType(TypeRep.Int) // hack + minVarName = names.mangle("min") + minVar <- impParadigm.imperativeCapabilities.declareVar(minVarName, intType, Some(maxValue)) + kStart <- explore(ds.inclusiveStart, symbolTable = symbolTable, bottomUp = Some(dp)) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(ds.variable), intType, Some(kStart)) + + resultVarName = names.mangle("result") + resultVar <- impParadigm.imperativeCapabilities.declareVar(resultVarName, intType, Some(zero)) + addedSymbolTable = symbolTable + ("min" -> minVar) + ("k" -> kVar) + ("result" -> resultVar) + + minCond <- arithmetic.arithmeticCapabilities.lt(resultVar, minVar) + guardCondition <- explore(ds.guardContinue, symbolTable = addedSymbolTable, bottomUp = Some(dp)) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + neg99 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -99) + + resultExpr <- explore(ds.subproblemExpression, symbolTable = addedSymbolTable, bottomUp = Some(dp)) + assignResult <- impParadigm.imperativeCapabilities.assignVar(resultVar, resultExpr) + + // record minimum + update <- impParadigm.imperativeCapabilities.ifThenElse(minCond, for { + updateResult <- impParadigm.imperativeCapabilities.assignVar(minVar, resultVar) + _ <- addBlockDefinitions(Seq(updateResult)) + // here is where one could store decisions + } yield (), Seq.empty, None) + + advExpr <- explore(ds.advance, symbolTable = addedSymbolTable, bottomUp = Some(dp)) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, update, kadv)) + } yield ()) + + assigned <- impParadigm.imperativeCapabilities.assignVar(dpij, minVar) + } yield Seq(whilestmt, assigned) + + case ds: MaxRangeDefinition => for { + maxValue <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, scala.Int.MaxValue) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + intType <- toTargetLanguageType(TypeRep.Int) // hack + maxVarName = names.mangle("max") + maxVar <- impParadigm.imperativeCapabilities.declareVar(maxVarName, intType, Some(maxValue)) + kStart <- explore(ds.inclusiveStart, symbolTable = symbolTable, bottomUp = Some(dp)) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(ds.variable), intType, Some(kStart)) + + resultVarName = names.mangle("result") + resultVar <- impParadigm.imperativeCapabilities.declareVar(resultVarName, intType, Some(zero)) + addedSymbolTable = symbolTable + ("max" -> maxVar) + ("k" -> kVar) + ("result" -> resultVar) + + maxCond <- arithmetic.arithmeticCapabilities.lt(maxVar, resultVar) + guardCondition <- explore(ds.guardContinue, symbolTable = addedSymbolTable, bottomUp = Some(dp)) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + + resultExpr <- explore(ds.subproblemExpression, symbolTable = addedSymbolTable, bottomUp = Some(dp)) + assignResult <- impParadigm.imperativeCapabilities.assignVar(resultVar, resultExpr) + + // record minimum + update <- impParadigm.imperativeCapabilities.ifThenElse(maxCond, for { + updateResult <- impParadigm.imperativeCapabilities.assignVar(maxVar, resultVar) + _ <- addBlockDefinitions(Seq(updateResult)) + // here is where one could store decisions + } yield (), Seq.empty, None) + + advExpr <- explore(ds.advance, symbolTable = addedSymbolTable, bottomUp = Some(dp)) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, update, kadv)) + } yield ()) + + assigned <- impParadigm.imperativeCapabilities.assignVar(dpij, maxVar) + } yield Seq(whilestmt, assigned) + + case sd: SumDefinition => for { + intType <- toTargetLanguageType(TypeRep.Int) + kStart <- explore(sd.inclusiveStart, symbolTable = symbolTable, bottomUp = Some(dp)) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.variable), intType, Some(kStart)) + + guardCondition <- explore(sd.guardContinue, symbolTable = symbolTable ++ Map(sd.variable -> kVar), bottomUp = Some(dp)) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + + resultExpr <- explore(sd.subproblemExpression, symbolTable = symbolTable ++ Map(sd.variable -> kVar), bottomUp = Some(dp)) + additive <- arithmetic.arithmeticCapabilities.add(dpij, resultExpr) + assignResult <- impParadigm.imperativeCapabilities.assignVar(dpij, additive) + + advExpr <- explore(sd.advance, symbolTable = symbolTable ++ Map(sd.variable -> kVar), bottomUp = Some(dp)) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, kadv)) + + } yield ()) + + } yield Seq(whilestmt) + + case sd:ReturnAccumulatedDefinition => + if (sd.iteration.length == 1) { + for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + intType <- toTargetLanguageType(TypeRep.Int) + kStart <- explore(sd.iteration.head.inclusiveStart, symbolTable = symbolTable, bottomUp = Some(dp)) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.iteration.head.variable), intType, Some(kStart)) + accVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.accumulationVariable), intType, Some(kStart)) + + guardCondition <- explore(sd.iteration.head.guardCondition, symbolTable = symbolTable ++ Map(sd.iteration.head.variable -> kVar, sd.accumulationVariable -> accVar), bottomUp = Some(dp)) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + + resultExpr <- explore(sd.subproblemExpression, symbolTable = symbolTable ++ Map(sd.iteration.head.variable -> kVar, sd.accumulationVariable -> accVar), bottomUp = Some(dp)) + additive <- arithmetic.arithmeticCapabilities.add(accVar, resultExpr) + assignResult <- impParadigm.imperativeCapabilities.assignVar(accVar, additive) + + advExpr <- explore(sd.iteration.head.advance, symbolTable = symbolTable ++ Map(sd.iteration.head.variable -> kVar, sd.accumulationVariable -> accVar), bottomUp = Some(dp)) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, kadv)) + + } yield ()) + + retStmt <- impParadigm.imperativeCapabilities.returnStmt(accVar) + } yield Seq(whilestmt, retStmt) + } else if (sd.iteration.length == 2) { + for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + + intType <- toTargetLanguageType(TypeRep.Int) + accVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.accumulationVariable), intType, Some(zero)) + + level0_low <- explore(sd.iteration.head.inclusiveStart, bottomUp = Some(dp), symbolTable = Map.empty, memoize = false) + level0_var <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.iteration.head.variable), intType, Some(level0_low)) + + // NOTE that other variables HIGH and LOW might depend on earlier variables, so build up symbol table + level1_map = Map(sd.iteration.head.variable -> level0_var, sd.accumulationVariable -> accVar) + + // "r" + level1_low <- explore(sd.iteration.tail.head.inclusiveStart, bottomUp = Some(dp), symbolTable = level1_map, memoize = false) + level1_var <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.iteration.tail.head.variable), intType, Some(level1_low)) + level2_map = level1_map ++ Map(sd.iteration.tail.head.variable -> level1_var) // HACK FIX, model.solution.mappers("i") -> expr1) + + level0_condition <- explore(sd.iteration.head.guardCondition, bottomUp = Some(dp), symbolTable = level2_map, memoize = false) + level1_condition <- explore(sd.iteration.tail.head.guardCondition, bottomUp = Some(dp), symbolTable = level2_map, memoize = false) + + // INNER LOOP + whileLoop_inner <- impParadigm.imperativeCapabilities.whileLoop(level1_condition, for { + resultExpr <- explore(sd.subproblemExpression, symbolTable=level2_map, bottomUp=Some(dp)) + additive <- arithmetic.arithmeticCapabilities.add(accVar, resultExpr) + assignResult <- impParadigm.imperativeCapabilities.assignVar(accVar, additive) + + _ <- addBlockDefinitions(Seq(assignResult)) + + ivar_inner_plusone <- arithmetic.arithmeticCapabilities.add(level1_var, one) + incr_inner <- impParadigm.imperativeCapabilities.assignVar(level1_var, ivar_inner_plusone) + + _ <- addBlockDefinitions(Seq(incr_inner)) + } yield ()) + + // OUTER LOOP + whileLoop_outer <- impParadigm.imperativeCapabilities.whileLoop(level0_condition, for { + inner_reset <- impParadigm.imperativeCapabilities.assignVar(level1_var, level1_low) + + ivar_outer_plusone <- arithmetic.arithmeticCapabilities.add(level0_var, one) + incr_outer <- impParadigm.imperativeCapabilities.assignVar(level0_var, ivar_outer_plusone) + _ <- addBlockDefinitions(Seq(inner_reset, whileLoop_inner, incr_outer)) + } yield ()) + + retStmt <- impParadigm.imperativeCapabilities.returnStmt(accVar) + } yield Seq(whileLoop_outer, retStmt) + } else { + ??? + } + + case _ => ??? + } + } + + /** + * Constructor now takes the responsibility of taking the arguments to the problem. Takes + * in a sequence of arguments, and auto-initializes all possible fields. + * + * args are "name", then "name_init", then TYPE. + * + * name_init would be the parameter to constructor; + * name is field in the class + * TYPE is type for both + */ + def create_bottom_up_constructor(args: Seq[(Name, Name, Type)]): Generator[ConstructorContext, Unit] = { + import ooParadigm.constructorCapabilities._ + + val formalArgs = args.map(arg => (arg._2, arg._3)) + val fieldArgs = args.map(arg => (arg._1, arg._3)) + + for { + _ <- setParameters(formalArgs) + real_args <- getArguments() + + _ <- forEach(real_args.zip(fieldArgs)) { pair => for { + _ <- initializeField(pair._2._1, pair._1._3) + } yield () + } + + } yield () + } + + def make_bottom_up(model:EnhancedModel): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + + // The approach might force an N-dimensional search space even when the input is only 1-dimensional (like MatrixChainMultiplication) + // |params| determines the dimensionality of the array dp[][] + val params = model.mode match { + case ut:UpperTriangle => ut.params + case _ => model.solution.order + } + + for { + arrayType <- toTargetLanguageType(arTypes(model)) + + _ <- forEach(model.input) { bexpr => for { + tpe <- map_type_in_class(bexpr.argType) + _ <- addField(names.mangle(bexpr.name), tpe) + } yield () + } + + _ <- addField(dpName, arrayType) // this becomes "int" if I use arrayType + + constArgs <- forEach(model.input) { bexpr => + for { + tpe <- map_type_in_class(bexpr.argType) + } yield (names.mangle(bexpr.name), names.mangle(bexpr.name + "_"), tpe) // in some OO languages, i.e., scala, param name must be different + } + _ <- addConstructor(create_bottom_up_constructor(constArgs)) + + // Trying to direct to appropriate place + _ <- addMethod(computeName, make_bottom_up_compute_method_recursive(model, params)) + + } yield None + } + + addClassToProject(makeClass, names.mangle(model.problem)) + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPMainJava.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPMainJava.scala new file mode 100644 index 00000000..9b73d0e0 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPMainJava.scala @@ -0,0 +1,112 @@ +package org.combinators.dp.enhanced + +/** + * sbt "dp/runMain org.combinators.dp.DPJavaDirectToDiskMain" + * + * Creates output files in target/dp + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.dp.TestExample +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.ep.language.java.paradigm.ObjectOriented +import org.combinators.ep.language.java.{CodeGenerator, JavaNameProvider, PartiallyBoxed, Syntax, Unboxed} +import org.combinators.models.* + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +abstract class EnhancedDPMainJava extends IOApp with EnhancedMainInterface { + val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = Unboxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("dp")))) + + val dpApproach = EnhancedDPObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.ooParadigm, generator.doublesInMethod, generator.realDoublesInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.mapsInMethod, generator.mapsInConstructor, generator.assertionsInMethod, generator.stringsInMethod, generator.equalityInMethod, generator.parametricPolymorphism, generator.booleansInMethod)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + // subclasses will provide tests and model + def tests:Seq[TestExample] + def model:EnhancedModel + + // subclasses describe how to instantiate desired app class + def constructApp(): EnhancedDPMainJava + + def filesToGenerate(option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doublesInMethod.enable() + _ <- generator.realDoublesInMethod.enable() + _ <- generator.intsInMethod.enable() + _ <- generator.stringsInMethod.enable() + _ <- generator.listsInMethod.enable() + _ <- generator.consoleInMethod.enable() + _ <- generator.arraysInMethod.enable() + _ <- generator.equalityInMethod.enable() + _ <- generator.assertionsInMethod.enable() + _ <- generator.booleansInMethod.enable() + _ <- generator.mapsInMethod.enable() + _ <- generator.mapsInConstructor.enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, tests, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, option) + } yield ExitCode.Success + } + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val choice = if (args.length == 1) { + args(0).toLowerCase() match { + case "topdown" => topDown + case "topdownwithmemo" => topDownWithMemo + case "topdownmemo" => topDownWithMemo + case "bottomup" => bottomUp + case _ => ??? + } + } else { + bottomUp + } + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { constructApp() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(Paths.get("target", "java", model.problem), choice) + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPMainScala.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPMainScala.scala new file mode 100644 index 00000000..1f2efe39 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPMainScala.scala @@ -0,0 +1,126 @@ +package org.combinators.dp.enhanced + +import cats.effect.{ExitCode, IO, IOApp} +import org.apache.commons.io.FileUtils +import org.combinators.ep.language.scala.ast.ffi.* +import org.combinators.ep.language.scala.ast.{FinalBaseAST, FinalNameProviderAST} +import org.combinators.ep.language.scala.codegen.CodeGenerator +import org.combinators.ep.language.scala.codegen.FullAST +import org.combinators.cogen.* +import org.combinators.cogen.FileWithPathPersistable +import org.combinators.cogen.FileWithPathPersistable.fileWithPathPersistable +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.EnhancedModel + +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +abstract class EnhancedDPMainScala extends IOApp with EnhancedMainInterface { + val _ast: FullAST = new FinalBaseAST + with FinalNameProviderAST + with FinalArithmeticAST + with FinalArraysAST + with FinalAssertionsAST + with FinalBooleanAST + with FinalConsoleAST + with FinalExceptionsAST + with FinalEqualsAST + with FinalListsAST + with FinalMapsAST + with FinalOperatorExpressionsAST + with FinalRealArithmeticOpsAST + with FinalStringAST { + val reificationExtensions = List.empty + } + val generator: CodeGenerator[_ast.type] = CodeGenerator("dp", _ast, Set.empty) + + val dpApproach = EnhancedDPObjectOrientedProvider[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.imperative.imperativeInMethods, generator.ooParadigm, generator.doubles.arithmeticInMethods, generator.realDoubles.realArithmeticInMethods, generator.console.consoleInMethods, generator.arrays.arraysInMethods, generator.maps.mapsInMethods, generator.maps.mapsIn[generator.ooParadigm.ConstructorContext], generator.assertions.assertionsInMethods, generator.strings.stringsInMethods, generator.equality.equalsInMethods, generator.parametricPolymorphism, generator.booleans.booleansInMethodsInMethods)(generator.generics) + + val persistable = FileWithPathPersistable[FileWithPath] + + // subclasses will provide tests and model + def tests:Seq[TestExample] + def model:EnhancedModel + + // subclasses describe how to instantiate desired app class + def constructApp(): EnhancedDPMainScala + + def filesToGenerate(option: GenerationOption): Seq[FileWithPath] = { + println(s"Generating ${model.problem}...") + generator.paradigm.runGenerator { + for { + _ <- generator.doubles.arithmeticInMethods.enable() + _ <- generator.realDoubles.realArithmeticInMethods.enable() + _ <- generator.ints.arithmeticInMethods.enable() + _ <- generator.strings.stringsInMethods.enable() + _ <- generator.lists.listsInMethods.enable() + _ <- generator.console.consoleInMethods.enable() + _ <- generator.arrays.arraysInMethods.enable() + _ <- generator.equality.equalsInMethods.enable() + _ <- generator.assertions.assertionsInMethods.enable() + _ <- generator.booleans.booleansInMethodsInMethods.enable() + _ <- generator.maps.mapsInMethods.enable() + _ <- generator.maps.mapsIn[generator.ooParadigm.ConstructorContext].enable() + + // HERE you can finally specify the method to use for testing and the test cases + _ <- dpApproach.implement(model, tests, option) + } yield () + } + } + + def directToDiskTransaction(targetDirectory: Path, option:GenerationOption): IO[Unit] = { + + IO { + print("Computing Files...") + val computed = filesToGenerate(option) + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path, option:GenerationOption): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, option) + } yield ExitCode.Success + } + + def run(args: List[String]): IO[ExitCode] = { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + val choice = if (args.length == 1) { + args(0).toLowerCase() match { + case "topdown" => topDown + case "topdownwithmemo" => topDownWithMemo + case "topdownmemo" => topDownWithMemo + case "bottomup" => bottomUp + case _ => ??? + } + } else { + bottomUp + } + + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { constructApp() } + _ <- IO { println("[OK]") } + + result <- main.runDirectToDisc(Paths.get("target", "scala", model.problem), choice) + } yield result + } +} + + diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPObjectOrientedProvider.scala new file mode 100644 index 00000000..abaf0fd3 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPObjectOrientedProvider.scala @@ -0,0 +1,350 @@ +package org.combinators.dp.enhanced + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{AbstractSyntax, NameProvider, TypeRep} +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, Maps, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} +import org.combinators.dp.TestExample +import org.combinators.models.{EnhancedModel, LiteralArray, LiteralBoolean, LiteralChar, LiteralExpression, LiteralInt, LiteralString, LiteralTuple} + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait EnhancedDPObjectOrientedProvider extends EnhancedDPProvider with EnhancedUtility with TopDownStrategy with BottomUpStrategy { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext, paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val maps: Maps.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + // if not memo, then this will be defined and added + lazy val resultVarName = names.mangle("result") + + import paradigm._ + import syntax._ + import ooParadigm._ + +// // expand as necessary +// def literalMapping(litExpr:LiteralExpression): Generator[MethodBodyContext, Expression] = { +// +// // only SINGLE values can go here +// litExpr match { +// case lit: LiteralInt => paradigm.methodBodyCapabilities.reify(TypeRep.Int, lit.literal) +// case bool: LiteralBoolean => paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, bool.literal) +// case str: LiteralString => paradigm.methodBodyCapabilities.reify(TypeRep.String, str.literal) +// case chr: LiteralChar => paradigm.methodBodyCapabilities.reify(TypeRep.Char, chr.literal) +// +// case _ => ??? // error in all other circumstances +// } +// } + + def testResult(answer:LiteralExpression) : Generator[MethodBodyContext, Expression] = { + answer match { + case lit: LiteralInt => paradigm.methodBodyCapabilities.reify(TypeRep.Int, lit.literal) + case bool: LiteralBoolean => paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, bool.literal) + case _ => ??? + } + } + + object VariableCounter { + private var count: Int = 1 + + // increment with each access. + def getAndIncrement(): Int = { + val current = count + count += 1 + current + } + + // Read-only access to current count, without incrementing + def currentCount: Int = count + } + + def instantiateSolutionArguments(input:LiteralExpression) : Generator[MethodBodyContext, Seq[Expression]] = { + import paradigm.methodBodyCapabilities._ + input match { + case litInt:LiteralInt => for { + value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, litInt.literal) + } yield Seq(value) + + case litStr:LiteralString => for { + value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, litStr.literal) + } yield Seq(value) + + case litArr:LiteralArray => + val type_rep = constructedArrayType(litArr.dimensions.length, TypeRep.Int) + for { + arrayType <- toTargetLanguageType(type_rep) + expr <- create_int_nd_array(litArr.literal, litArr.dimensions) + variable <- impParadigm.imperativeCapabilities.declareVar(names.mangle("ar" + VariableCounter.getAndIncrement()), arrayType, Some(expr)) + } yield Seq(variable) + + case litTuple:LiteralTuple => + for { + others <- forEach(litTuple.values) { aLit => + for { + out <- instantiateSolutionArguments(aLit) + } yield out + } + } yield others.flatMap(_.toSeq) // Flattens all into single sequence + + case _ => ??? + } + } + + def testType(answer:LiteralExpression) : Generator[MethodBodyContext, Type] = { + import paradigm.methodBodyCapabilities._ + answer match { + case _: LiteralInt => toTargetLanguageType(TypeRep.Int) + case _: LiteralChar => toTargetLanguageType(TypeRep.Char) + case _: LiteralBoolean => toTargetLanguageType(TypeRep.Boolean) + case _: LiteralString => toTargetLanguageType(TypeRep.String) + case _ => ??? + } + } + + def genericTests(implementation: String, tests: Seq[TestExample]): Generator[MethodBodyContext, Seq[Expression]] = { + import eqls.equalityCapabilities._ + import paradigm.methodBodyCapabilities._ + + for { + assertStatements <- forEach(tests) { test => + for { + solType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) + args <- instantiateSolutionArguments(test.inputType) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, args) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) + sol_actual <- apply(computeMethod, Seq.empty) + sol_value <- testResult(test.answer) + theType <- testType(test.answer) + + assertStmt <- asserts.assertionCapabilities.assertEquals(theType, sol_actual, sol_value) + } yield assertStmt + } + } yield assertStatements + } + + +// def generateTests(implementation:String, tests: Seq[TestExample]): Generator[MethodBodyContext, Seq[Expression]] = { +// import eqls.equalityCapabilities._ +// import paradigm.methodBodyCapabilities._ +// for { +// assert_statements <- forEach(tests) { test => +// +// val the_test_type = test.answer match { +// case _:LiteralInt => toTargetLanguageType(TypeRep.Int) +// case _:LiteralChar => toTargetLanguageType(TypeRep.Char) +// case _:LiteralBoolean => toTargetLanguageType(TypeRep.Boolean) +// case _:LiteralString => toTargetLanguageType(TypeRep.String) +// case _ => ??? +// } +// +// // Should be carefully redesigned to treat Input as sequence of values, each of which is independently handled +// // 1. paradigm.methodBodyCapabilities.reify(TypeRep.SOMETHING, SOMEVALUE) +// // 2. Arrays can have multiple dimensions and require ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(variable)) +// // +// // Paradigm is to put all arguments into constructor to yield `sol` object, and then call compute() with no arguments. +// // Long-term goal is to convert all multiple arguments (i.e., LiteralStringTriple) into Tuples, each individually constructed +// // and make these LiteralTuple() whose type is TupleType() +// +// // Arrays have to be handled specially, I'm afraid +// val createArray = test.inputType match { +// case _:LiteralArray => +// true +// //////case _:LiteralArrayPair => true +// case _ => false +// } +// +// // if > 0 then this is a sequence of parameters +// val sequenceLength = test.inputType match { +// //////case lt:LiteralTriple => Seq(lt.val1, lt.val2, lt.val3) +// //////case lp:LiteralPair => Seq(lp.val1, lp.val2) +// case _ => Seq(3) // Seq.empty +// } +// +// val createStrings = test.inputType match { +// /////case _:LiteralStringTriple => true +// /////case _:LiteralStringPair => true +// case _ => false +// } +// +// for { +// solType <- ooParadigm.methodBodyCapabilities.findClass(names.mangle(implementation)) +// sol <- if (createArray) { +// val vals = test.inputType match { +// case la:LiteralArray => Seq(la.literal) +// //////case la:LiteralArrayPair => Seq(la.ar1, la.ar2) +// case _ => Seq.empty +// } +// +// val dimensions = test.inputType match { +// case la:LiteralArray => +// la.dimensions +// ////// case lap:LiteralArrayPair => +// ////// Seq(lap.ar1.length) // these are two one-dimensional arrays that must be same length. +// case _ => Seq.empty +// } +// +// val type_rep = constructedArrayType(dimensions.length, TypeRep.Int) +// +// if (vals.length == 1) { +// for { +// arrayType <- toTargetLanguageType(type_rep) +// expr <- create_int_nd_array(vals.head, dimensions) +// variable <- impParadigm.imperativeCapabilities.declareVar(names.mangle(test.name), arrayType, Some(expr)) +// sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(variable)) +// } yield sol +// } else if (vals.length == 2) { +// for { +// arrayType <- toTargetLanguageType(type_rep) +// expr1 <- create_int_nd_array(vals.head, dimensions) +// expr2 <- create_int_nd_array(vals.tail.head, dimensions) +// var1 <- impParadigm.imperativeCapabilities.declareVar(names.mangle(test.name + "1"), arrayType, Some(expr1)) +// var2 <- impParadigm.imperativeCapabilities.declareVar(names.mangle(test.name + "2"), arrayType, Some(expr2)) +// sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(var1, var2)) +// } yield sol +// } else { +// ??? +// } +// } else if (createStrings) { +// val vals = test.inputType match { +// ///// case triple:LiteralStringTriple => Seq(triple.string1, triple.string2, triple.string3) +// /// case pair:LiteralStringPair => Seq(pair.string1, pair.string2) +// case _ => Seq("") // JUST FOR NOW Seq.empty +// } +// +// for { +// all <- forEach (vals) { v1 => +// for { +// v1_val <- paradigm.methodBodyCapabilities.reify(TypeRep.String, v1) +// } yield v1_val +// } +// sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, all) +// } yield sol +// } else { +// if (sequenceLength.isEmpty) { +// for { +// litval <- literalMapping(test.inputType) +// sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(litval)) +// } yield sol +// } else if(sequenceLength.length == 2) { +// for { +// arg1 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, sequenceLength(0)) +// arg2 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, sequenceLength(1)) +// sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(arg1, arg2)) +// } yield sol +// } else if (sequenceLength.length == 3) { +// for { +// arg1 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, sequenceLength(0)) +// arg2 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, sequenceLength(1)) +// arg3 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, sequenceLength(2)) +// sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solType, Seq(arg1, arg2, arg3)) +// } yield sol +// } else { +// ??? +// } +// } +// +// // Everything has led to this point, to assert that new Solution(...).compute() generates desired sol_gen_value +// computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, computeName) +// sol_actual <- apply(computeMethod, Seq.empty) +// sol_value <- testResult(test.answer) +// theType <- the_test_type +// asserteq_fib <- asserts.assertionCapabilities.assertEquals(theType, sol_actual, sol_value) +// +// } yield asserteq_fib +// } +// } yield assert_statements +// } + + def makeTestCase(clazzName:String, tests:Seq[TestExample]): Generator[TestContext, Unit] = { + for { + _ <- paradigm.testCapabilities.addTestCase(genericTests(clazzName, tests), names.mangle(clazzName)) + } yield () + } + + /** Trying out some new capabilities */ + def implement(model: EnhancedModel, tests:Seq[TestExample], option:GenerationOption): Generator[ProjectContext, Unit] = { + + // handle Top/Bottom and properly set memo when TD + var isTopDown = false + var useMemo = false + option match { + case td:TopDown => + useMemo = td.memo + isTopDown = true + + case _:BottomUp => + isTopDown = false + } + + for { + // The code below generates the actual class, based on model.problem + _ <- if (isTopDown) { + make_top_down(useMemo, model) + } else { + make_bottom_up(model) + } + + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(names.mangle("Test" + model.problem), makeTestCase(model.problem, tests)), + names.mangle("Test" + model.problem) + ) + } yield () + } +} + +object EnhancedDPObjectOrientedProvider { + type WithParadigm[P <: AnyParadigm] = EnhancedDPObjectOrientedProvider { val paradigm: P } + type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] + + def apply[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] + (base: P) + (nameProvider: NameProvider[base.syntax.Name], + imp: Imperative.WithBase[base.MethodBodyContext, base.type], + oo: ObjectOriented.WithBase[base.type], + ffiArithmetic: Arithmetic.WithBase[base.MethodBodyContext, base.type, Double], + ffiRealArithmetic: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double], + con: Console.WithBase[base.MethodBodyContext, base.type], + arr: Arrays.WithBase[base.MethodBodyContext, base.type], + mps: Maps.WithBase[base.MethodBodyContext, base.type], + mpsInConst: Maps.WithBase[oo.ConstructorContext, base.type], + assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], + stringsIn: Strings.WithBase[base.MethodBodyContext, base.type], + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + parametricPolymorphism: ParametricPolymorphism.WithBase[base.type], + booleansIn: Booleans.WithBase[base.MethodBodyContext, base.type] + ) + (generics: Generics.WithBase[base.type, oo.type, parametricPolymorphism.type]): EnhancedDPObjectOrientedProvider.WithParadigm[base.type] = + new EnhancedDPObjectOrientedProvider { + override val paradigm: base.type = base + val impParadigm: imp.type = imp + val arithmetic: ffiArithmetic.type = ffiArithmetic + val realArithmetic: ffiRealArithmetic.type = ffiRealArithmetic + override val names: NameProvider[paradigm.syntax.Name] = nameProvider + override val ooParadigm: oo.type = oo + override val polymorphics: parametricPolymorphism.type = parametricPolymorphism + override val genericsParadigm: generics.type = generics + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con + override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr + override val maps: Maps.WithBase[base.MethodBodyContext, paradigm.type] = mps + override val mapsInConstructors: Maps.WithBase[ooParadigm.ConstructorContext, paradigm.type] = mpsInConst + override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn + override val strings: Strings.WithBase[base.MethodBodyContext, paradigm.type] = stringsIn + override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val booleans: Booleans.WithBase[base.MethodBodyContext, paradigm.type] = booleansIn + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPProvider.scala new file mode 100644 index 00000000..d644ecbf --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedDPProvider.scala @@ -0,0 +1,19 @@ +package org.combinators.dp.enhanced + +import org.combinators.dp.TestExample +import org.combinators.cogen.Command._ +import org.combinators.cogen.NameProvider +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.dp.original.GenerationOption +import org.combinators.models.EnhancedModel + +/** Attempt to provide a dynamic programming world generator. */ +trait EnhancedDPProvider { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + import paradigm._ + + /** Entry point into code generation. */ + def implement(model:EnhancedModel, tests:Seq[TestExample], option:GenerationOption): Generator[ProjectContext, Unit] +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedMainInterface.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedMainInterface.scala new file mode 100644 index 00000000..8c89f7ad --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedMainInterface.scala @@ -0,0 +1,15 @@ +package org.combinators.dp.enhanced + +import org.combinators.cogen.FileWithPath +import org.combinators.dp.original.GenerationOption +import org.combinators.models.EnhancedModel + +/** + * Presents the ability to generate files from an EnhancedModel. + * + * This allows for customized *MainJava and *MainScalafiles. + */ +trait EnhancedMainInterface { + def model: EnhancedModel + def filesToGenerate(option: GenerationOption): Seq[FileWithPath] +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedUtility.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedUtility.scala new file mode 100644 index 00000000..4758b1b3 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/EnhancedUtility.scala @@ -0,0 +1,125 @@ +package org.combinators.dp.enhanced + +import org.combinators.models.{BooleanType, CharType, EnhancedModel, IntegerType, StringType} +import org.combinators.cogen.TypeRep +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.NameProvider +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Equality, RealArithmetic, Strings} + +trait EnhancedUtility { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm._ + import syntax._ + import ooParadigm._ + + def constructedArrayType(level:Int, baseType:TypeRep): TypeRep = { + level match { + case 0 => baseType + case value: Int => + val inner:TypeRep = constructedArrayType(value-1, baseType) + TypeRep.Array(inner) + + } + } + + def return_type_based_on_model(model:EnhancedModel) : Generator[MethodBodyContext, Type] = { + import paradigm.methodBodyCapabilities._ + + model.subproblemType match { + case _:IntegerType => for { + intType <- toTargetLanguageType(TypeRep.Int) + } yield intType + + case _:CharType => for { + charType <- toTargetLanguageType(TypeRep.Char) + } yield charType + + case _:BooleanType => for { + boolType <- toTargetLanguageType(TypeRep.Boolean) + } yield boolType + + case _:StringType => for { + strType <- toTargetLanguageType(TypeRep.String) + } yield strType + + case _ => ??? + } + } + +// def helper_method_type(model:EnhancedModel) : Generator[MethodBodyContext, Type] = { +// import paradigm.methodBodyCapabilities._ +// +// model.subproblemType match { +// case _:IntegerType => for { +// intType <- toTargetLanguageType(TypeRep.Int) +// } yield intType +// +// case _:CharType => for { +// charType <- toTargetLanguageType(TypeRep.Char) +// } yield charType +// +// case _:BooleanType => for { +// boolType <- toTargetLanguageType(TypeRep.Boolean) +// } yield boolType +// +// case _:StringType => for { +// strType <- toTargetLanguageType(TypeRep.String) +// } yield strType +// +// case _ => ??? +// } +// } + +// def helper_method_type_in_class(model:EnhancedModel) : TypeRep = { +// +// model.subproblemType match { +// case _:IntegerType => TypeRep.Int +// case _:CharType => TypeRep.Char +// case _:BooleanType => TypeRep.Boolean +// case _:StringType => TypeRep.String +// +// case _ => ??? +// } +// } + + def helper_default(model:EnhancedModel) : Generator[MethodBodyContext, Expression ] = { + + model.subproblemType match { + case _: IntegerType => for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + } yield zero + + case _: BooleanType => for { + falseValue <- paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, false) + } yield falseValue + + case _ => ??? + } + } + + def helper_problemType(model:EnhancedModel) : TypeRep = { + import ooParadigm.constructorCapabilities._ + + model.subproblemType match { + case _:IntegerType => TypeRep.Int + case _:CharType => TypeRep.Char + case _:BooleanType => TypeRep.Boolean + case _:StringType => TypeRep.String + + case _ => ??? + } + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/TopDownStrategy.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/TopDownStrategy.scala new file mode 100644 index 00000000..dfc591ef --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/enhanced/TopDownStrategy.scala @@ -0,0 +1,580 @@ +package org.combinators.dp.enhanced + +import org.combinators.cogen.TypeRep +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.* +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism, ToTargetLanguageType} +import org.combinators.cogen.{Command, NameProvider} +import org.combinators.dp.original.Utility +import org.combinators.models.* + +/** + * Concepts necessary to realize top-down solutions + */ + +trait TopDownStrategy extends Utility with EnhancedUtility { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val maps: Maps.WithBase[paradigm.MethodBodyContext, paradigm.type] + val mapsInConstructors: Maps.WithBase[ooParadigm.ConstructorContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm._ + import paradigm._ + import syntax._ + + lazy val memoFunctionName = names.mangle("memo") // function name + lazy val memoMapName = names.mangle("memoMap") // storage + lazy val keyName = names.mangle("key") + lazy val pairName = names.mangle("pair") + + lazy val computedResult = names.mangle("computed_result") + + /** Debugging statement to add inside a for { ... } by using `_ <- report_td(str)` */ + def report_td(str:String) : Generator[paradigm.MethodBodyContext, Unit] = { + println(str) + for { + ne77 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -77) + } yield () + } + + /** + private int memo(ARGUMENTS) { + int key = pair(ARGUMENTS) + if (this.memo.containsKey(n)) { + return this.memo.get(n); + } + + int result = helper(n); + this.memo.put(n, result); + return result; + } + */ + def memo_helper_body(model:EnhancedModel): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + // need to convert into a KEY method. MUST have at least one argument + args <- getArguments() + allExpressions <- forEach(args) { arg => for { + _ <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -97) // There needs to be at least one of these before "=" next + expr = arg._3 + } yield expr + } + + intType <- toTargetLanguageType(TypeRep.Int) + helperType = helper_problemType(model) + self <- ooParadigm.methodBodyCapabilities.selfReference() + memo_field <- ooParadigm.methodBodyCapabilities.getMember(self, memoMapName) + + pair_func <- ooParadigm.methodBodyCapabilities.getMember(self, pairName) + + key_var <- if (args.length == 1) { + impParadigm.imperativeCapabilities.declareVar(keyName, intType, Some(args.head._3)) + } else if (args.length == 2) { + for { + pair_expr <- paradigm.methodBodyCapabilities.apply(pair_func, allExpressions) + } yield pair_expr + } else { + // fold everything in, after calling pair() on the final two parameters + val base_expr = paradigm.methodBodyCapabilities.apply(pair_func, allExpressions.slice(allExpressions.length - 2, allExpressions.length)) + allExpressions.slice(0, allExpressions.length - 2).foldRight(base_expr)((acc, index) => for { + expr <- index + expanded <- paradigm.methodBodyCapabilities.apply(pair_func, Seq(acc, expr)) + } yield expanded) + } + + //memo_ck <- ooParadigm.methodBodyCapabilities.getMember(memo_field, names.mangle("containsKey")) + //memo_cond_expr <- paradigm.methodBodyCapabilities.apply(memo_ck, Seq(key_var)) + memo_cond_expr <- maps.mapCapabilities.contains(memo_field, key_var) + + check_if <- impParadigm.imperativeCapabilities.ifThenElse(memo_cond_expr, for { +// get_method <- ooParadigm.methodBodyCapabilities.getMember(memo_field, names.mangle("get")) +// get_call <- paradigm.methodBodyCapabilities.apply(get_method, Seq(key_var)) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + helper_default <- helper_default(model) + get_call <- maps.mapCapabilities.getOrElse(memo_field, key_var, helper_default) + stmt1 <- impParadigm.imperativeCapabilities.returnStmt(get_call) + _ <- addBlockDefinitions(Seq(stmt1)) + } yield None, Seq.empty) + _ <- addBlockDefinitions(Seq(check_if)) + + helper_method <- ooParadigm.methodBodyCapabilities.getMember(self, helperName) + + helper_expr <- paradigm.methodBodyCapabilities.apply(helper_method, allExpressions) + actual_type <- toTargetLanguageType(helperType) + result_var <- impParadigm.imperativeCapabilities.declareVar(computedResult, actual_type, Some(helper_expr)) + + self <- ooParadigm.methodBodyCapabilities.selfReference() + memo_field <- ooParadigm.methodBodyCapabilities.getMember(self, memoMapName) +// put_method <- ooParadigm.methodBodyCapabilities.getMember(memo_field, names.mangle("put")) +// func_call <- paradigm.methodBodyCapabilities.apply(put_method, Seq(key_var, result_var)) +// + func_call <- maps.mapCapabilities.put(memo_field, intType, intType, key_var, result_var) + stmt1 <- impParadigm.imperativeCapabilities.assignVar(memo_field, func_call) + //stmt1 <- impParadigm.imperativeCapabilities.liftExpression(func_call) + _ <- addBlockDefinitions(Seq(stmt1)) + + } yield Some(result_var) + } + +// /** +// * Create the MemoType, which is always HashMap because the solution to a DP is an integer, and +// * you can convert the subproblem arguments into an Integer using Cantor's pairing function. +// */ +// def make_memo_type(keyType:Type, valueType:Type): Generator[ConstructorContext, Type] = { +// import genericsParadigm.constructorCapabilities._ +// import ooParadigm.constructorCapabilities._ +// +// for { +// mapClass <- toTargetLanguageType(TypeRep.Map(keyType, valueType)) +// +// finalTpe <- applyType(mapClass, Seq(keyType, valueType)) +// +// } yield finalTpe +// } + + /** + * Constructor now takes the responsibility of taking the arguments to the problem. Takes + * in a sequence of arguments, and auto-initializes all possible fields. + * + * args are "name", then "name_init", then TYPE. + * + * name_init would be the parameter to constructor; + * name is field in the class + * TYPE is type for both + */ + def createConstructor(model:EnhancedModel, useMemo:Boolean, args: Seq[(Name, Name, Type)]): Generator[ConstructorContext, Unit] = { + import ooParadigm.constructorCapabilities._ + + val formalArgs = args.map(arg => (arg._2, arg._3)) + val fieldArgs = args.map(arg => (arg._1, arg._3)) + + for { + _ <- setParameters(formalArgs) + real_args <- getArguments() // these now contain the "_init" expressions + + _ <- forEach(real_args.zip(fieldArgs)) { pair => for { + _ <- initializeField(pair._2._1, pair._1._3) + } yield () + } + + _ <- if (useMemo) { + for { + intType <- toTargetLanguageType(TypeRep.Int) + helperType = helper_problemType(model) + actualType <- toTargetLanguageType(helperType) + obj <- mapsInConstructors.mapCapabilities.create(intType, actualType) + //obj <- maps.mapCapabilities.create(intType, intType) + _ <- initializeField(memoMapName, obj) + } yield None + } else { + Command.skip[ConstructorContext] + } + } yield () + } + + def make_top_down(useMemo:Boolean, model:EnhancedModel): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities._ + + def makeMemo(keyTypeRep:TypeRep, valueTypeRep:TypeRep) : Generator[ClassContext, Unit] = { + import classCapabilities._ + import genericsParadigm.classCapabilities._ + + for { +// mapClass <- ooParadigm.classCapabilities.findClass( +// names.mangle("java"), names.mangle("util"), names.mangle("HashMap") +// ) + actual_type <- toTargetLanguageType(TypeRep.Map(keyTypeRep, valueTypeRep)) + + _ <- addField(memoMapName, actual_type) + } yield None + } + + def create_memo_helper(): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + for { + _ <- symbol_table_from_solution(model.solution) // Needed to set params for memo + retType = helper_problemType(model) + actual_type <- toTargetLanguageType(retType) + _ <- setReturnType(actual_type) + res <- memo_helper_body(model) + } yield res + } + + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities._ + for { + _ <- forEach(model.input) { bexpr => for { + tpe <- map_type_in_class(bexpr.argType) + _ <- addField(names.mangle(bexpr.name), tpe) + } yield () + } + + _ <- if (useMemo) { + val returnType = helper_problemType(model) + for { + _ <- makeMemo(TypeRep.Int, returnType) + } yield () + } else { + Command.skip[ClassContext] + } + constArgs <- forEach(model.input) { bexpr => + for { + tpe <- map_type_in_class(bexpr.argType) + } yield (names.mangle(bexpr.name), names.mangle(bexpr.name + "_"), tpe) // in some OO languages, i.e., scala, param name must be different + } + + _ <- addConstructor(createConstructor(model, useMemo, constArgs)) // FIX HACK + + _ <- if (useMemo) { + for { + _ <- addMethod(memoFunctionName, create_memo_helper()) + _ <- addMethod(pairName, pair_helper()) + } yield () + } else { + Command.skip[ClassContext] + } + + _ <- addMethod(helperName, outer_helper(useMemo, model)) + _ <- addMethod(computeName, make_compute_method(model)) + } yield None + } + + addClassToProject(makeClass, names.mangle(model.problem)) + } + + /** + * Necessary wrapper method that inserts a return (expr) statement from the given expression. Needed for top-down, non-memo + */ + private def expand(exp: Expression): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities._ + val s:Seq[Statement] = Seq.empty + for { + av <- impParadigm.imperativeCapabilities.returnStmt(exp) + _ <- addBlockDefinitions(Seq(av)) + } yield None + } + + def exploreReturns(defs:DefinitionStatement, symbolTable: Map[String,Expression], memoize:Boolean = false) : Generator[paradigm.MethodBodyContext, Seq[Statement]] = { + defs match { + case es:ExpressionStatement => for { + e <- explore(es.expr, memoize=memoize, symbolTable=symbolTable) + av <- impParadigm.imperativeCapabilities.returnStmt(e) + } yield Seq(av) + + case _ => ??? + } + } + + def generate (defn:Definition, symbolTable: Map[String,Expression], memoize:Boolean = false) : Generator[paradigm.MethodBodyContext, Seq[Statement]] = { + import paradigm.methodBodyCapabilities._ + + case class TraversalInformation( + statements:Seq[Statement], + symbols:Map[String,Expression]) + + // return (Seq[statement] containing whileloop(s) and then seq of high vars, to be used by instantiation + def traverse_inwards(accVar:Expression, level:Int, sd:ReturnAccumulatedDefinition, symbolTable:Map[String, Expression]): Generator[MethodBodyContext, TraversalInformation] = { + if (level < 0) { + for { + resultExpr <- explore(sd.subproblemExpression, symbolTable=symbolTable, memoize=memoize) + additive <- arithmetic.arithmeticCapabilities.add(accVar, resultExpr) + assignResult <- impParadigm.imperativeCapabilities.assignVar(accVar, additive) + } yield TraversalInformation(Seq(assignResult), symbolTable) + } else { + for { + intType <- toTargetLanguageType(TypeRep.Int) + + level_low <- explore(sd.iteration(level).inclusiveStart, symbolTable=symbolTable, memoize=memoize) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + level_var <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.iteration(level).variable), intType, Some(zero)) + level_map = symbolTable + (sd.iteration(level).variable -> level_var) + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + traversalInfo <- traverse_inwards(accVar, level - 1, sd, level_map) + + level_condition <- explore(sd.iteration(level).guardCondition, symbolTable=level_map, memoize=memoize) + + // reset counter variable + loop_var_decl <- impParadigm.imperativeCapabilities.assignVar(level_var, level_low) + level_whileLoop <- impParadigm.imperativeCapabilities.whileLoop(level_condition, for { + _ <- addBlockDefinitions(traversalInfo.statements) + + level_var_plusone <- arithmetic.arithmeticCapabilities.add(level_var, one) + incr_inner <- impParadigm.imperativeCapabilities.assignVar(level_var, level_var_plusone) + + _ <- addBlockDefinitions(Seq(incr_inner)) + } yield ()) + } yield TraversalInformation(Seq(loop_var_decl,level_whileLoop), traversalInfo.symbols) + } + } + + defn match { + case ed:ExpressionDefinition => for { + expr <- explore(ed.expr, symbolTable = symbolTable, memoize=memoize) + retval <- impParadigm.imperativeCapabilities.returnStmt(expr) + } yield Seq(retval) + + // same as ExpressionDefinition -- difference only materializes in TopDown + case ed:ReturnExpressionDefinition => for { + expr <- explore(ed.expr, symbolTable = symbolTable, memoize=memoize) + retval <- impParadigm.imperativeCapabilities.returnStmt(expr) + } yield Seq(retval) + + case ite:IfThenElseDefinition => for { + inner <- explore(ite.condition, memoize = false, symbolTable = symbolTable) + ifstmt <- impParadigm.imperativeCapabilities.ifThenElse( + // condition of first if + inner + , + // statements for that first if + for { + stmts <- exploreReturns(ite.result, symbolTable = symbolTable, memoize=memoize) + _ <- addBlockDefinitions(stmts) + } yield () + , + // collection of (condition, block) for all remaining cases + Seq.empty + , + // terminating 'else' takes the elseCase and adds it last + Some(for { + stmts <- generate(ite.elseExpression, symbolTable=symbolTable, memoize=memoize) + _ <- addBlockDefinitions(stmts) + } yield ()) + ) + } yield Seq(ifstmt) + + case ds:MinRangeDefinition => for { + maxValue <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, scala.Int.MaxValue) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + intType <- toTargetLanguageType(TypeRep.Int) // perhaps acceptable to consider 'min' will be an integer + minVarName = names.mangle("min") + minVar <- impParadigm.imperativeCapabilities.declareVar(minVarName, intType, Some(maxValue)) + kStart <- explore(ds.inclusiveStart, symbolTable=symbolTable, memoize=memoize) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(ds.variable), intType, Some(kStart)) + + resultVarName = names.mangle("result") + resultVar <- impParadigm.imperativeCapabilities.declareVar(resultVarName, intType, Some(zero)) + addedSymbolTable = symbolTable + ("min" -> minVar) + (ds.variable -> kVar) + ("result" -> resultVar) + + minCond <- arithmetic.arithmeticCapabilities.lt(resultVar, minVar) + guardCondition <- explore(ds.guardContinue, symbolTable=addedSymbolTable, memoize=memoize) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + + resultExpr <- explore(ds.subproblemExpression, symbolTable=addedSymbolTable, memoize=memoize) + assignResult <- impParadigm.imperativeCapabilities.assignVar(resultVar, resultExpr) + + // record minimum + update <- impParadigm.imperativeCapabilities.ifThenElse(minCond, for { + updateResult <- impParadigm.imperativeCapabilities.assignVar(minVar, resultVar) + _ <- addBlockDefinitions(Seq(updateResult)) + // here is where one could store decisions + } yield (), Seq.empty, None) + + advExpr <- explore(ds.advance, symbolTable=addedSymbolTable, memoize=memoize) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, update, kadv)) + } yield ()) + + returnResult <- impParadigm.imperativeCapabilities.returnStmt(minVar) + } yield Seq(whilestmt, returnResult) + + case ds:MaxRangeDefinition => for { + minValue <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, scala.Int.MinValue) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + intType <- toTargetLanguageType(TypeRep.Int) // perhaps acceptable to consider 'min' will be an integer + maxVarName = names.mangle("max") + maxVar <- impParadigm.imperativeCapabilities.declareVar(maxVarName, intType, Some(minValue)) + kStart <- explore(ds.inclusiveStart, symbolTable=symbolTable, memoize=memoize) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(ds.variable), intType, Some(kStart)) + + resultVarName = names.mangle("result") + resultVar <- impParadigm.imperativeCapabilities.declareVar(resultVarName, intType, Some(zero)) + addedSymbolTable = symbolTable + ("max" -> maxVar) + (ds.variable -> kVar) + ("result" -> resultVar) + + maxCond <- arithmetic.arithmeticCapabilities.lt(maxVar, resultVar) + guardCondition <- explore(ds.guardContinue, symbolTable=addedSymbolTable, memoize=memoize) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + + resultExpr <- explore(ds.subproblemExpression, symbolTable=addedSymbolTable, memoize=memoize) + assignResult <- impParadigm.imperativeCapabilities.assignVar(resultVar, resultExpr) + + // record minimum + update <- impParadigm.imperativeCapabilities.ifThenElse(maxCond, for { + updateResult <- impParadigm.imperativeCapabilities.assignVar(maxVar, resultVar) + _ <- addBlockDefinitions(Seq(updateResult)) + // here is where one could store decisions + } yield (), Seq.empty, None) + + advExpr <- explore(ds.advance, symbolTable=addedSymbolTable, memoize=memoize) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, update, kadv)) + } yield ()) + + returnResult <- impParadigm.imperativeCapabilities.returnStmt(maxVar) + } yield Seq(whilestmt, returnResult) + + // SAME implementation as SumDefinition: only difference will be in BottomUp + case sd:ReturnAccumulatedDefinition => + for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + intType <- toTargetLanguageType(TypeRep.Int) + accVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.accumulationVariable), intType, Some(zero)) + symbolTable = Map(sd.accumulationVariable -> accVar) + + traversalInfo <- traverse_inwards(accVar, sd.iteration.length - 1, sd, symbolTable) + + _ <- addBlockDefinitions(traversalInfo.statements) + + retStmt <- impParadigm.imperativeCapabilities.returnStmt(accVar) + } yield Seq(retStmt) + + // below could summarily be extended with its own traverse_in + case sd:SumDefinition => for { + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + intType <- toTargetLanguageType(TypeRep.Int) // perhaps acceptable to consider 'min' will be an integer + sumVarName = names.mangle("sum") + sumVar <- impParadigm.imperativeCapabilities.declareVar(sumVarName, intType, Some(zero)) + + intType <- toTargetLanguageType(TypeRep.Int) // perhaps acceptable to consider 'min' will be an integer + kStart <- explore(sd.inclusiveStart, symbolTable=symbolTable, memoize=memoize) + kVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(sd.variable), intType, Some(kStart)) + + guardCondition <- explore(sd.guardContinue, symbolTable=symbolTable ++ Map(sd.variable -> kVar), memoize=memoize) + whilestmt <- impParadigm.imperativeCapabilities.whileLoop(guardCondition, for { + + resultExpr <- explore(sd.subproblemExpression, symbolTable=symbolTable ++ Map(sd.variable -> kVar), memoize=memoize) + additive <- arithmetic.arithmeticCapabilities.add(sumVar, resultExpr) + assignResult <- impParadigm.imperativeCapabilities.assignVar(sumVar, additive) + + advExpr <- explore(sd.advance, symbolTable=symbolTable ++ Map(sd.variable -> kVar), memoize=memoize) + kadv <- impParadigm.imperativeCapabilities.assignVar(kVar, advExpr) + _ <- addBlockDefinitions(Seq(assignResult, kadv)) + } yield ()) + + returnResult <- impParadigm.imperativeCapabilities.returnStmt(sumVar) + } yield Seq(whilestmt, returnResult) + + case _ => ??? + } + } + + /** + * The workhorse for a top-down helper method that relies on recursion and base cases to do the work. + * The model has a sequence of `cases` that may contain logical guard and an expression that is to be the reulst + * for those cases. + * + * This code relies on a helper method and ensures that all base cases are resolved by return statements, and + * the final "else" case is appended. + * + * The explore() method converts a model Expression into a CoGen expression. Must be sure to pass in memo + * + * @return + */ + def process_inner_helper(useMemo:Boolean, model:EnhancedModel): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import AnyParadigm.syntax._ + import paradigm.methodBodyCapabilities._ + + + // could possibly have a definition that has NONE as the guard. None for now. + + for { + symbolTable <- symbol_table_from_solution(model.solution) + ifstmt <- generate(model.definition, symbolTable, memoize=useMemo) + _ <- addBlockDefinitions(ifstmt) + + } yield None + } + + /** + * Creates function using parameters from model and returns int: + * + * int SOMEFUNCTION (ARGS) + * + * where ARGS represents the model (i.e., (("n", Int)) for Fibonacci and (("s1", String), ("s2", String)) for LCS + */ + def symbol_table_from_solution(solution:SubproblemInvocation): Generator[paradigm.MethodBodyContext, Map[String, Expression]] = { + import paradigm.methodBodyCapabilities._ + + val real_params = solution.helpers.toSeq.filter(p => solution.order.contains(p._1)) + + // can add to mapargs from mappers info + + // Type of helper method param is always an integer to refer to earlier subproblem + for { + params <- forEach(real_params.toSeq) { pair => for { + argType <- toTargetLanguageType(TypeRep.Int) // Always will be int since subproblems are ordered + argName = names.mangle(pair._1) // use pre-selected iterator + } yield (argName, argType) + } + _ <- setParameters(params) + args <- getArguments() + + // make available in symbol table ALL, not just what's in signature + helperargs <- forEach(solution.helpers.toSeq zip args) { pair => + for { + argType <- toTargetLanguageType(TypeRep.Int) // needed syntactically because of the "=" usages below, and will be ignored. + argExpr = pair._2._3 + argName = pair._1._1 + } yield (argName, argExpr) + } + + mapperargs <- forEach(solution.mappers.toSeq) { pair => + for { + argExpr <- explore(pair._2, symbolTable = helperargs.toMap) + argName = pair._1 + } yield (argName, argExpr) + } + + } yield helperargs.toMap ++ mapperargs.toMap + } + + /** + * Method creates compute() method with no arguments that invokes helper method: + * + * public Integer compute() { + * return this.helper(this.n); + * } + * + * RETURN is taken right from the 'answer' field of the problem definition. + * + * REALLY only for TOP DOWN and perhaps could be moved... + */ + def make_compute_method(model:EnhancedModel): Generator[MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + + for { + returnType <- return_type_based_on_model(model) + _ <- setReturnType(returnType) + + av <- generate(model.answer, symbolTable=Map.empty) + _ <- addBlockDefinitions(av) + + } yield None + } + + def outer_helper(useMemo: Boolean, model:EnhancedModel): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities._ + for { + realType <- return_type_based_on_model(model) + _ <- setReturnType(realType) + + _ <- process_inner_helper(useMemo, model) + } yield None + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/fix_bottomup.py b/dynamicProgramming/src/main/scala/org/combinators/dp/fix_bottomup.py new file mode 100644 index 00000000..7f609bc6 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/fix_bottomup.py @@ -0,0 +1,40 @@ +""" + +I modified the fix_topdown to replace "int[]" with "Integer[]" throughout + +MAKE SURE you do this only in a directory that was generated. No Longer Needed + +""" +import os + +def process_java_file(path): + with open(path, "r", encoding="utf-8") as f: + lines = f.readlines() + + replaced = [] + updated = False + for line in lines: + if 'int[][]' in line: + replaced.append(line.replace('int[][]', 'Integer[][]')) + updated = True + elif 'int[]' in line: + replaced.append(line.replace('int[]', 'Integer[]')) + updated = True + else: + replaced.append(line) + + if updated: + print(f"Updated: {path}") + with open(path, "w", encoding="utf-8") as f: + f.writelines(replaced) + +def process_directory(root_dir): + for root, _, files in os.walk(root_dir): + for file in files: + if file.endswith(".java"): + process_java_file(os.path.join(root, file)) + +if __name__ == "__main__": + # Change this to your target subdirectory + target_directory = os.getcwd() + process_directory(target_directory) diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/fix_topdown.py b/dynamicProgramming/src/main/scala/org/combinators/dp/fix_topdown.py new file mode 100644 index 00000000..a915e7d8 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/fix_topdown.py @@ -0,0 +1,54 @@ +""" +I got the following script from chatgpt using this prompt: + +'can you give me a python script that adds "import java.util.*" to the beginning of all +Java files in a subdirectory, paying careful attention to do so after the "package" declaration.' + +Not too shabby. I only modified the final line to use os.getcwd() + +MAKE SURE you do this only in a directory that was generated. + +""" +import os + +IMPORT_LINE = "import java.util.*;\n" + +def process_java_file(path): + with open(path, "r", encoding="utf-8") as f: + lines = f.readlines() + + # Skip if the import already exists + if any(line.strip() == "import java.util.*;" for line in lines): + return + + insert_index = 0 + + # If there's a package declaration, insert after it + for i, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith("package ") and stripped.endswith(";"): + insert_index = i + 1 + break + + # Insert import (with a newline if needed for cleanliness) + if insert_index < len(lines) and lines[insert_index].strip() != "": + lines.insert(insert_index, "\n") + insert_index += 1 + + lines.insert(insert_index, IMPORT_LINE) + + with open(path, "w", encoding="utf-8") as f: + f.writelines(lines) + + print(f"Updated: {path}") + +def process_directory(root_dir): + for root, _, files in os.walk(root_dir): + for file in files: + if file.endswith(".java"): + process_java_file(os.path.join(root, file)) + +if __name__ == "__main__": + # Change this to your target subdirectory + target_directory = os.getcwd() + process_directory(target_directory) diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/original/BottomUpStrategy.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/original/BottomUpStrategy.scala new file mode 100644 index 00000000..b8976c3b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/original/BottomUpStrategy.scala @@ -0,0 +1,449 @@ +package org.combinators.dp.original + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.* +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{Command, NameProvider, TypeRep} +import org.combinators.models.* +import org.combinators.models.original.Model + +/** + * Concepts necessary to realize top-down solutions + */ + +trait BottomUpStrategy extends Utility { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm.* + import paradigm.* + import syntax.* + + lazy val iName = names.mangle("i") + lazy val nName = names.mangle("n") + lazy val dpName = names.mangle("dp") + + // will need to be expanded to depth-10 or something + lazy val arTypes = Seq(TypeRep.Int, + TypeRep.Array(TypeRep.Int), + TypeRep.Array(TypeRep.Array(TypeRep.Int)), + TypeRep.Array(TypeRep.Array(TypeRep.Array(TypeRep.Int))), + TypeRep.Array(TypeRep.Array(TypeRep.Array(TypeRep.Array(TypeRep.Int)))), + ) + + /** Needed when working bottom up. */ + private def expand_assign(dp_i:Expression, exp: Expression): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities.* + for { + av <- impParadigm.imperativeCapabilities.assignVar(dp_i, exp) + _ <- addBlockDefinitions(Seq(av)) + } yield None + } + + def make_bottom_up_compute_method_nest_3(model: Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + + val real_cases = model.cases.filter(p => p._1.isDefined) // MUST be at least one. + val first_case = real_cases.head + val tail_cases = real_cases.tail + val elseCase = model.cases.filter(p => p._1.isEmpty) // MUST only be one. + + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + + arrayType <- toTargetLanguageType(arTypes(model.bounds.length)) + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + // Get max bounds for all three dimensions + max_bound_outer <- max_bound_in_method(model.bounds.head) + mboplus1 <- arithmetic.arithmeticCapabilities.add(max_bound_outer, one) + + max_bound_middle <- max_bound_in_method(model.bounds.tail.head) + mbmplus1 <- arithmetic.arithmeticCapabilities.add(max_bound_middle, one) + + max_bound_inner <- max_bound_in_method(model.bounds.tail.tail.head) + mbiplus1 <- arithmetic.arithmeticCapabilities.add(max_bound_inner, one) + + // Declare iteration variables for all three dimensions + ivar_outer <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.head.itArgName), intType, Some(zero)) + ivar_middle <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.tail.head.itArgName), intType, Some(zero)) + ivar_inner <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.tail.tail.head.itArgName), intType, Some(zero)) + + // Access dp array at all three levels + dp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + dp_o <- array.arrayCapabilities.get(dp, Seq(ivar_outer)) + dp_o_m <- array.arrayCapabilities.get(dp_o, Seq(ivar_middle)) + dp_o_m_i <- array.arrayCapabilities.get(dp_o_m, Seq(ivar_inner)) + + // Build symbol table with all three iteration variables + symbol_table = Map( + model.bounds.head.itArgName -> ivar_outer, + model.bounds.tail.head.itArgName -> ivar_middle, + model.bounds.tail.tail.head.itArgName -> ivar_inner + ) + + // Instantiate 3D array + instantiated <- array.arrayCapabilities.create(intType /* arrayType*/, Seq(mboplus1, mbmplus1, mbiplus1), None) + + inner <- explore(first_case._1.get, bottomUp = Some(dp), symbolTable = symbol_table) + + all_rest <- forEach(tail_cases) { next_case => + for { + next_cond <- explore(next_case._1.get, memoize = false, bottomUp = Some(dp), symbolTable = symbol_table) + next_exp <- explore(next_case._2, memoize = false, bottomUp = Some(dp), symbolTable = symbol_table) + } yield (next_cond, expand_assign(dp_o_m_i, next_exp)) + } + + assign_stmt <- impParadigm.imperativeCapabilities.assignVar(dp, instantiated) + _ <- addBlockDefinitions(Seq(assign_stmt)) + + // Range conditions for all three dimensions + in_range <- arithmetic.arithmeticCapabilities.le(ivar_inner, max_bound_inner) + middle_range <- arithmetic.arithmeticCapabilities.le(ivar_middle, max_bound_middle) + out_range <- arithmetic.arithmeticCapabilities.le(ivar_outer, max_bound_outer) + + // Innermost while loop (inner dimension) + whileLoop_inner <- impParadigm.imperativeCapabilities.whileLoop(in_range, for { + ifstmt <- impParadigm.imperativeCapabilities.ifThenElse( + inner, + for { + resexp <- explore(first_case._2, memoize = false, bottomUp = Some(dp), symbolTable = symbol_table) + av <- impParadigm.imperativeCapabilities.assignVar(dp_o_m_i, resexp) + _ <- addBlockDefinitions(Seq(av)) + } yield None, + all_rest, + Some(for { + result_exp <- explore(elseCase.head._2, memoize = false, bottomUp = Some(dp), symbolTable = symbol_table) + av <- impParadigm.imperativeCapabilities.assignVar(dp_o_m_i, result_exp) + _ <- addBlockDefinitions(Seq(av)) + } yield ()) + ) + + ivar_inner_plusone <- arithmetic.arithmeticCapabilities.add(ivar_inner, one) + incr_inner <- impParadigm.imperativeCapabilities.assignVar(ivar_inner, ivar_inner_plusone) + + _ <- addBlockDefinitions(Seq(ifstmt, incr_inner)) + } yield ()) + + // Middle while loop + whileLoop_middle <- impParadigm.imperativeCapabilities.whileLoop(middle_range, for { + inner_reset <- impParadigm.imperativeCapabilities.assignVar(ivar_inner, zero) + + ivar_middle_plusone <- arithmetic.arithmeticCapabilities.add(ivar_middle, one) + incr_middle <- impParadigm.imperativeCapabilities.assignVar(ivar_middle, ivar_middle_plusone) + + _ <- addBlockDefinitions(Seq(inner_reset, whileLoop_inner, incr_middle)) + } yield ()) + + // Outermost while loop + whileLoop_outer <- impParadigm.imperativeCapabilities.whileLoop(out_range, for { + middle_reset <- impParadigm.imperativeCapabilities.assignVar(ivar_middle, zero) + inner_reset <- impParadigm.imperativeCapabilities.assignVar(ivar_inner, zero) + + ivar_outer_plusone <- arithmetic.arithmeticCapabilities.add(ivar_outer, one) + incr_outer <- impParadigm.imperativeCapabilities.assignVar(ivar_outer, ivar_outer_plusone) + + _ <- addBlockDefinitions(Seq(middle_reset, inner_reset, whileLoop_middle, incr_outer)) + } yield ()) + + _ <- addBlockDefinitions(Seq(whileLoop_outer)) + + // Return last element dp[max_bound_outer][max_bound_middle][max_bound_inner] + dpexp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + dpo <- array.arrayCapabilities.get(dpexp, Seq(max_bound_outer)) + dpm <- array.arrayCapabilities.get(dpo, Seq(max_bound_middle)) + dpi <- array.arrayCapabilities.get(dpm, Seq(max_bound_inner)) + retstmt <- Command.lift(dpi) + } yield Some(retstmt) + } + + // This is hard-coded for TWO bounds. + def make_bottom_up_compute_method_nest_2(model:Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + + val real_cases = model.cases.filter(p => p._1.isDefined) // MUST be at least one. + val first_case = real_cases.head + val tail_cases = real_cases.tail + val elseCase = model.cases.filter(p => p._1.isEmpty) // MUST only be one. Not sure how I would check + + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + // ONLY ONE HERE + arrayType <- toTargetLanguageType(arTypes(model.bounds.length)) + + // cannot seem to do this in Constructor because it insists on using "int" for TypeRep.Int within ConstructorContext which + // seems to be different from Integer which occurs in MethodBodyContext + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + max_bound_outer <- max_bound_in_method(model.bounds.head) + mboplus1 <- arithmetic.arithmeticCapabilities.add(max_bound_outer, one) + + max_bound_inner <- max_bound_in_method(model.bounds.tail.head) + mbiplus1 <- arithmetic.arithmeticCapabilities.add(max_bound_inner, one) + + ivar_outer <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.head.itArgName), intType, Some(zero)) + ivar_inner <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.tail.head.itArgName), intType, Some(zero)) + + dp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + dp_o <- array.arrayCapabilities.get(dp, Seq(ivar_outer)) + dp_o_i <- array.arrayCapabilities.get(dp_o, Seq(ivar_inner)) + i_map = Map(model.bounds.head.itArgName -> ivar_outer) + j_map = Map(model.bounds.tail.head.itArgName -> ivar_inner) + + // just wanted to test out (dead code) how maps can be folded and used. This is a template for building + // up a symbol table when nesting computations. + ij_map = i_map ++ j_map + other_data = Seq(i_map, j_map) + total_map = other_data.foldLeft(Map.empty[String, Expression]) { (acc, a_map) => acc ++ a_map } + oi_map = Map(model.bounds.head.itArgName -> ivar_outer, model.bounds.tail.head.itArgName -> ivar_inner) + + instantiated <- array.arrayCapabilities.create(intType /* arrayType*/, Seq(mboplus1,mbiplus1), None) + inner <- explore(first_case._1.get, bottomUp = Some(dp), symbolTable = oi_map) // get from Model + + all_rest <- forEach(tail_cases) { next_case => + for { + next_cond <- explore(next_case._1.get, memoize = false, bottomUp = Some(dp), symbolTable= oi_map) + next_exp <- explore(next_case._2, memoize = false, bottomUp = Some(dp), symbolTable= oi_map) + } yield (next_cond, expand_assign(dp_o_i, next_exp)) + } + + assign_stmt <- impParadigm.imperativeCapabilities.assignVar (dp, instantiated) + _ <- addBlockDefinitions(Seq(assign_stmt)) + in_range <- arithmetic.arithmeticCapabilities.le(ivar_inner, max_bound_inner) + + out_range <- arithmetic.arithmeticCapabilities.le(ivar_outer, max_bound_outer) + + whileLoop_inner <- impParadigm.imperativeCapabilities.whileLoop(in_range, for { + + ifstmt <- impParadigm.imperativeCapabilities.ifThenElse( + // condition of first if + inner + , + // statements for that first if + for { + resexp <- explore(first_case._2, memoize = false, bottomUp = Some(dp), symbolTable= oi_map) + av <- impParadigm.imperativeCapabilities.assignVar(dp_o_i, resexp) + _ <- addBlockDefinitions(Seq(av)) + } yield None + , + // collection of (condition, block) for all remaining cases + all_rest + , + // terminating 'else' takes the elseCase and adds it last + Some(for { + result_exp <- explore(elseCase.head._2, memoize = false, bottomUp = Some(dp), symbolTable= oi_map) + av <- impParadigm.imperativeCapabilities.assignVar(dp_o_i, result_exp) + _ <- addBlockDefinitions(Seq(av)) + } yield ()) + ) + + ivar_inner_plusone <- arithmetic.arithmeticCapabilities.add(ivar_inner, one) + incr_inner <- impParadigm.imperativeCapabilities.assignVar(ivar_inner, ivar_inner_plusone) + + _ <- addBlockDefinitions(Seq(ifstmt, incr_inner)) + } yield ()) + + whileLoop_outer <- impParadigm.imperativeCapabilities.whileLoop(out_range, for { + inner_reset <- impParadigm.imperativeCapabilities.assignVar(ivar_inner, zero) + + ivar_outer_plusone <- arithmetic.arithmeticCapabilities.add(ivar_outer, one) + incr_outer <- impParadigm.imperativeCapabilities.assignVar(ivar_outer, ivar_outer_plusone) + _ <- addBlockDefinitions(Seq(inner_reset, whileLoop_inner, incr_outer)) + } yield ()) + + _ <- addBlockDefinitions(Seq(whileLoop_outer)) + + ij = Seq(ivar_outer, ivar_inner) + + + + // return last element dp[n] because dp has n+1 elements + dpexp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + dpo <- array.arrayCapabilities.get(dpexp, Seq(max_bound_outer)) + dpi <- array.arrayCapabilities.get(dpo, Seq(max_bound_inner)) + retstmt <- Command.lift(dpi) + } yield Some(retstmt) + } + + + // This is hard-coded for a SINGLE bound. We will need another one to deal with two-d problems (and higher) + def make_bottom_up_compute_method(model:Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + + val real_cases = model.cases.filter(p => p._1.isDefined) // MUST be at least one. + val first_case = real_cases.head + val tail_cases = real_cases.tail + val elseCase = model.cases.filter(p => p._1.isEmpty) // MUST only be one. Not sure how I would check + + for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + + // ONLY ONE HERE + arrayType <- toTargetLanguageType(arTypes(model.bounds.length)) + + // cannot seem to do this in Constructor because it insists on using "int" for TypeRep.Int within ConstructorContext which + // seems to be different from Integer which occurs in MethodBodyContext + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + max_bound <- max_bound_in_method(model.bounds.head) + mbplus1 <- arithmetic.arithmeticCapabilities.add(max_bound, one) + + ivar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.head.itArgName), intType, Some(zero)) + + dp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + dp_i <- array.arrayCapabilities.get(dp, Seq(ivar)) + + instantiated <- array.arrayCapabilities.create(intType /* arrayType*/, Seq(mbplus1), None) + + inner <- explore(first_case._1.get, bottomUp = Some(dp), symbolTable = Map(model.bounds.head.itArgName -> ivar)) // get from Model + + all_rest <- forEach(tail_cases) { next_case => + for { + next_cond <- explore(next_case._1.get, memoize = false, bottomUp = Some(dp), symbolTable = Map("i" -> ivar)) + next_exp <- explore(next_case._2, memoize = false, bottomUp = Some(dp), symbolTable = Map("i" -> ivar)) + } yield (next_cond, expand_assign(dp_i, next_exp)) + } + + assign_stmt <- impParadigm.imperativeCapabilities.assignVar (dp, instantiated) + _ <- addBlockDefinitions(Seq(assign_stmt)) + in_range <- arithmetic.arithmeticCapabilities.le(ivar, max_bound) + + whileLoop <- impParadigm.imperativeCapabilities.whileLoop(in_range, for { + ifstmt <- impParadigm.imperativeCapabilities.ifThenElse( + // condition of first if + inner + , + // statements for that first if + for { + resexp <- explore(first_case._2, memoize = false, bottomUp = Some(dp), symbolTable = Map("i" -> ivar)) + av <- impParadigm.imperativeCapabilities.assignVar(dp_i, resexp) + _ <- addBlockDefinitions(Seq(av)) + } yield None + , + // collection of (condition, block) for all remaining cases + all_rest + , + // terminating 'else' takes the elseCase and adds it last + Some(for { + result_exp <- explore(elseCase.head._2, memoize = false, bottomUp = Some(dp), symbolTable = Map("i" -> ivar)) + av <- impParadigm.imperativeCapabilities.assignVar(dp_i, result_exp) + _ <- addBlockDefinitions(Seq(av)) + } yield ()) + ) + + ivarplusone <- arithmetic.arithmeticCapabilities.add(ivar, one) + incr <- impParadigm.imperativeCapabilities.assignVar(ivar, ivarplusone) + + _ <- addBlockDefinitions(Seq(ifstmt, incr)) + } yield ()) + + _ <- addBlockDefinitions(Seq(whileLoop)) + + // return last element dp[n] because dp is n+1 in size + dpexp <- ooParadigm.methodBodyCapabilities.getMember(self, dpName) + dpn <- array.arrayCapabilities.get(dpexp, Seq(max_bound)) + retstmt <- Command.lift(dpn) + } yield Some(retstmt) + } + + + /** + * Constructor now takes the responsibility of taking the arguments to the problem. Takes + * in a sequence of arguments, and auto-initializes all possible fields. + */ + def create_bottom_up_constructor(args: Seq[(Name, Type)]): Generator[ConstructorContext, Unit] = { + import ooParadigm.constructorCapabilities.* + + for { + _ <- setParameters(args) + real_args <- getArguments() + + _ <- forEach(real_args) { arg => for { + _ <- initializeField(arg._1, arg._3) + } yield () + } + + // one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + // nplus1 <- arithmetic.arithmeticCapabilities.add(real_args.head._3, one) + // arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + + // instantiated <- ooParadigm.methodBodyCapabilities.instantiateObject(arrayType, Seq(nplus1), None) + // self <- selfReference() + + // I CANNOT GET THIS TO WORK + + //dp <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle("dp")) + //_ <- initializeField(names.mangle("dp"), instantiated) + + // assign_stmt <- impParadigm.imperativeCapabilities.assignVar (dp, instantiated) + // _ <- addBlockDefinitions(Seq(assign_stmt)) + + } yield () + } + + def make_bottom_up(model:Model): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities.* + + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities.* + + for { + arrayType <- toTargetLanguageType(arTypes(model.bounds.length)) + + _ <- forEach(model.bounds) { bexpr => for { + tpe <- map_type_in_class(bexpr.argType) + _ <- addField(names.mangle(bexpr.name), tpe) + } yield () + } + + _ <- addField(dpName, arrayType) // this becomes "int" if I use arrayType + + constArgs <- forEach(model.bounds) { bexpr => + for { + tpe <- map_type_in_class(bexpr.argType) + } yield (names.mangle(bexpr.name), tpe) + } + _ <- addConstructor(create_bottom_up_constructor(constArgs)) + + _ <- if (model.bounds.length == 1) { + addMethod(computeName, make_bottom_up_compute_method(model)) + } else if (model.bounds.length == 2) { + addMethod(computeName, make_bottom_up_compute_method_nest_2(model) ) + } else { + for { + _ <- addMethod(computeName, make_bottom_up_compute_method_nest_3(model)) + _ <- addMethod(retrieveName, generate_retrieve(model)) + } yield None + + } + } yield None + } + + addClassToProject(makeClass, names.mangle(model.problem)) + } + +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/original/DPObjectOrientedProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/original/DPObjectOrientedProvider.scala new file mode 100644 index 00000000..f094d39b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/original/DPObjectOrientedProvider.scala @@ -0,0 +1,94 @@ +package org.combinators.dp.original + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{NameProvider, TypeRep} +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Booleans, Console, Equality, RealArithmetic, Strings} +import org.combinators.cogen.paradigm.{Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.dp.original.{BottomUpStrategy, DPProvider, TopDownStrategy} +import org.combinators.models.original.Model + +/** Any OO approach will need to properly register type mappings and provide a default mechanism for finding a class + * in a variety of contexts. This trait provides that capability + */ +trait DPObjectOrientedProvider extends DPProvider with Utility with TopDownStrategy with BottomUpStrategy { + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val names: NameProvider[paradigm.syntax.Name] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val console: Console.WithBase[paradigm.MethodBodyContext,paradigm.type] + val array: Arrays.WithBase[paradigm.MethodBodyContext,paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import paradigm.* + import syntax.* + + // if not memo, then this will be defined and added + lazy val resultVarName = names.mangle("result") + + /** + * Method creates compute() method with no arguments that invokes helper method: + * + * public Integer compute() { + * return this.helper(this.n); + * } + */ + def make_compute_method(model:Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + for { + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + self <- ooParadigm.methodBodyCapabilities.selfReference() + helperMethod <- ooParadigm.methodBodyCapabilities.getMember(self, helperName) + + // convert arguments into Iteration values + args <- forEach(model.bounds) { boundExpr => for { + arg1 <- max_bound_in_method(boundExpr) + } yield arg1 + } + //field <- ooParadigm.methodBodyCapabilities.getMember(self, nName) + invocation <- apply(helperMethod, args) + } yield Some(invocation) + } + + // must be implemented by another -- the test cases refer to the class name passed in as the implementation + def makeTestCase(implementation:String): Generator[TestContext, Unit] + + /** Trying out some new capabilities */ + def implement(model: Model, option:GenerationOption): Generator[ProjectContext, Unit] = { + // new stuff goes here. + // handle Top/Bottom and properly set memo when TD + var isTopDown = false + var useMemo = false + option match { + case td:TopDown => + useMemo = td.memo + isTopDown = true + + case _:BottomUp => + isTopDown = false + } + + for { + // The code below generates the actual class, based on model.problem + _ <- if (isTopDown) { + make_top_down(useMemo, model) + } else { + make_bottom_up(model) + } + + _ <- paradigm.projectCapabilities.addCompilationUnit( + paradigm.compilationUnitCapabilities.addTestSuite(names.mangle("Test" + model.problem), makeTestCase(model.problem)) + ) + } yield () + } + +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/original/DPProvider.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/original/DPProvider.scala new file mode 100644 index 00000000..e0f21660 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/original/DPProvider.scala @@ -0,0 +1,19 @@ +package org.combinators.dp.original + +import org.combinators.cogen.Command.* +import org.combinators.cogen.NameProvider +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.models.original.Model + +/** Attempt to provide a dynamic programming world generator. */ +trait DPProvider { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + import paradigm.* + + /** Entry point into code generation. */ + def implement(model:Model, option:GenerationOption): Generator[ProjectContext, Unit] + +} + diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/original/TopDownStrategy.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/original/TopDownStrategy.scala new file mode 100644 index 00000000..cb0109ae --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/original/TopDownStrategy.scala @@ -0,0 +1,297 @@ +package org.combinators.dp.original + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.* +import org.combinators.cogen.paradigm.{AnyParadigm, Generics, ObjectOriented, ParametricPolymorphism} +import org.combinators.cogen.{Command, NameProvider, TypeRep} +import org.combinators.models.* +import org.combinators.models.original.Model +/** + * Concepts necessary to realize top-down solutions + */ + +trait TopDownStrategy extends Utility { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val polymorphics: ParametricPolymorphism.WithBase[paradigm.type] + val genericsParadigm: Generics.WithBase[paradigm.type, ooParadigm.type, polymorphics.type] + + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm.* + import paradigm.* + import syntax.* + + // Definition of the name of the helper method + + lazy val memoName = names.mangle("memo") + lazy val keyName = names.mangle("key") + lazy val pairName = names.mangle("pair") + + lazy val computedResult = names.mangle("computed_result") + + // is provided by the DP common provider -- neither a topDown nor a bottomUp concept + def make_compute_method(model:Model): Generator[paradigm.MethodBodyContext, Option[Expression]] + + def create_key(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + for { + args <- getArguments() + + } yield None + } + + /** + private int memo(ARGUMENTS) { + if (this.memo.containsKey(n)) { + return this.memo.get(n); + } + + int result = helper(n); + this.memo.put(n, result); + return result; + } + */ + def memo_helper(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + for { + // need to convert into a KEY method. MUST have at least one argument + args <- getArguments() + intType <- toTargetLanguageType(TypeRep.Int) + self <- ooParadigm.methodBodyCapabilities.selfReference() + memo_field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle("memo")) + + memo_ck <- ooParadigm.methodBodyCapabilities.getMember(memo_field, names.mangle("containsKey")) + memo_cond_expr <- paradigm.methodBodyCapabilities.apply(memo_ck, Seq(args.head._3)) + check_if <- impParadigm.imperativeCapabilities.ifThenElse(memo_cond_expr, for { + get_method <- ooParadigm.methodBodyCapabilities.getMember(memo_field, names.mangle("get")) + get_call <- paradigm.methodBodyCapabilities.apply(get_method, Seq(args.head._3)) + stmt1 <- impParadigm.imperativeCapabilities.returnStmt(get_call) + _ <- addBlockDefinitions(Seq(stmt1)) + } yield None, Seq.empty) + _ <- addBlockDefinitions(Seq(check_if)) + + helper_method <- ooParadigm.methodBodyCapabilities.getMember(self, helperName) + helper_expr <- paradigm.methodBodyCapabilities.apply(helper_method, Seq(args.head._3)) + result_var <- impParadigm.imperativeCapabilities.declareVar(computedResult, intType, Some(helper_expr)) + + self <- ooParadigm.methodBodyCapabilities.selfReference() + memo_field <- ooParadigm.methodBodyCapabilities.getMember(self, memoName) + put_method <- ooParadigm.methodBodyCapabilities.getMember(memo_field, names.mangle("put")) + + func_call <- paradigm.methodBodyCapabilities.apply(put_method, Seq(args.head._3, result_var)) + stmt1 <- impParadigm.imperativeCapabilities.liftExpression(func_call) + _ <- addBlockDefinitions(Seq(stmt1)) + + } yield Some(result_var) + } + + /** + * Create the MemoType, which is always HashMap because the solution to a DP is an integer, and + * you can convert the subproblem arguments into an Integer using Cantor's pairing function. + */ + def make_memo_type(keyType:TypeRep, valueType:TypeRep): Generator[ConstructorContext, Type] = { + import genericsParadigm.constructorCapabilities.* + import ooParadigm.constructorCapabilities.* + + for { + mapClass <- ooParadigm.constructorCapabilities.findClass( + names.mangle("java"), names.mangle("util"), names.mangle("HashMap") + ) + + keyType <- toTargetLanguageType(keyType) + valueType <- toTargetLanguageType(valueType) + finalTpe <- applyType(mapClass, Seq(keyType, valueType)) + + } yield finalTpe + } + + /** + * Constructor now takes the responsibility of taking the arguments to the problem. Takes + * in a sequence of arguments, and auto-initializes all possible fields. + */ + def createConstructor(useMemo:Boolean, args: Seq[(Name, Type)]): Generator[ConstructorContext, Unit] = { + import ooParadigm.constructorCapabilities.* + + for { + _ <- setParameters(args) + real_args <- getArguments() + + _ <- forEach(real_args) { arg => for { + _ <- initializeField(arg._1, arg._3) + } yield () + } + + _ <- if (useMemo) { + for { + tpe <- make_memo_type(TypeRep.Int, TypeRep.Int) // Key is key() result, and Value is DP-int solution + obj <- instantiateObject(tpe, Seq.empty) + _ <- initializeField(memoName, obj) + } yield None + } else { + Command.skip[ConstructorContext] + } + } yield () + } + + def make_top_down(useMemo:Boolean, model:Model): Generator[ProjectContext, Unit] = { + import ooParadigm.projectCapabilities.* + + def makeMemo(keyType:TypeRep, valueType:TypeRep) : Generator[ClassContext, Unit] = { + import classCapabilities.* + import genericsParadigm.classCapabilities.* + + for { + mapClass <- ooParadigm.classCapabilities.findClass( + names.mangle("java"), names.mangle("util"), names.mangle("HashMap") + ) + keyType <- toTargetLanguageType(keyType) + valueType <- toTargetLanguageType(valueType) + finalTpe <- applyType(mapClass, Seq(keyType, valueType)) + + _ <- addField(memoName, finalTpe) + } yield None + } + + def create_memo_helper(): Generator[MethodBodyContext, Option[Expression]] = { + for { + _ <- make_helper_method_signature(model.bounds) // should be done outside + res <- memo_helper() + } yield res + } + + val makeClass: Generator[ClassContext, Unit] = { + import classCapabilities.* + for { + intType <- toTargetLanguageType(TypeRep.Int) // shouldn't be hard-coded: should be able to infer from model + + _ <- forEach(model.bounds) { bexpr => for { + tpe <- map_type_in_class(bexpr.argType) + _ <- addField(names.mangle(bexpr.name), tpe) + } yield () + } + + _ <- if (useMemo) { + makeMemo(TypeRep.Int, TypeRep.Int) + } else { + Command.skip[ClassContext] + } + constArgs <- forEach(model.bounds) { bexpr => + for { + tpe <- map_type_in_class(bexpr.argType) + } yield (names.mangle(bexpr.name), tpe) + } + + _ <- addConstructor(createConstructor(useMemo, constArgs)) // FIX HACK + + _ <- if (useMemo) { + addMethod(keyName, create_key()) + addMethod(memoName, create_memo_helper()) + addMethod(pairName, pair_helper()) + } else { + Command.skip[ClassContext] + } + + _ <- addMethod(helperName, outer_helper(useMemo, model)) + _ <- addMethod(computeName, make_compute_method(model)) + } yield None + } + + addClassToProject(makeClass, names.mangle(model.problem)) + } + + /** + * Necessary wrapper method that inserts a return (expr) statement from the given expression. Needed for top-down, non-memo + */ + private def expand(exp: Expression): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities.* + for { + av <- impParadigm.imperativeCapabilities.returnStmt(exp) + _ <- addBlockDefinitions(Seq(av)) + } yield None + } + + /** + * The workhorse for a top-down helper method that relies on recursion and base cases to do the work. + * The model has a sequence of `cases` that may contain logical guard and an expression that is to be the reulst + * for those cases. + * + * This code relies on a helper method and ensures that all base cases are resolved by return statements, and + * the final "else" case is appended. + * + * The explore() method converts a model Expression into a CoGen expression. Must be sure to pass in memo + * The expand() method converts a model Expression into a Return statement of that expression + * + * @return + */ + def process_inner_helper(useMemo:Boolean, model:Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import AnyParadigm.syntax.* + import paradigm.methodBodyCapabilities.* + + val real_cases = model.cases.filter(p => p._1.isDefined) // MUST be at least one. + val first_case = real_cases.head + val tail_cases = real_cases.tail + val elseCase = model.cases.filter(p => p._1.isEmpty) // MUST only be one. Not sure how I would check + + for { + _ <- make_helper_method_signature(model.bounds) + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + inner <- explore(first_case._1.get, memoize=useMemo, symbolTable = Map.empty) + + all_rest <- forEach(tail_cases) { next_case => + for { + next_cond <- explore(next_case._1.get, memoize=useMemo, symbolTable = Map.empty) + next_exp <- explore(next_case._2, memoize=useMemo, symbolTable = Map.empty) + } yield (next_cond, expand(next_exp)) + } + + ifstmt <- impParadigm.imperativeCapabilities.ifThenElse( + // condition of first if + inner + , + // statements for that first if + for { + resexp <- explore(first_case._2, memoize=useMemo, symbolTable = Map.empty) + av <- impParadigm.imperativeCapabilities.returnStmt(resexp) + _ <- addBlockDefinitions(Seq(av)) + } yield None + , + // collection of (condition, block) for all remaining cases + all_rest + , + // terminating 'else' takes the elseCase and adds it last + Some(for { + result_exp <- explore(elseCase.head._2, memoize=useMemo, symbolTable = Map.empty) + av <- impParadigm.imperativeCapabilities.returnStmt(result_exp) + _ <- addBlockDefinitions(Seq(av)) + } yield ()) + ) + + _ <- addBlockDefinitions(Seq(ifstmt)) + } yield None + } + + def outer_helper(useMemo: Boolean, model:Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + for { + _ <- make_helper_method_signature(model.bounds) + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + _ <- process_inner_helper(useMemo, model) + } yield None + } + + + +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/dp/original/Utility.scala b/dynamicProgramming/src/main/scala/org/combinators/dp/original/Utility.scala new file mode 100644 index 00000000..f4e7e0a5 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/dp/original/Utility.scala @@ -0,0 +1,750 @@ +package org.combinators.dp.original + +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.paradigm.AnyParadigm.syntax.forEach +import org.combinators.cogen.paradigm.control.Imperative +import org.combinators.cogen.paradigm.ffi.* +import org.combinators.cogen.paradigm.{AnyParadigm, ObjectOriented} +import org.combinators.cogen.{Command, NameProvider, TypeRep} +import org.combinators.models.* +import org.combinators.models.original.Model + +// Different approach +trait GenerationOption { + def name:String +} + +case class TopDown(memo:Boolean = false) extends GenerationOption { + def name:String = if (memo) { "topDownMemo" } else { "topDown" } +} + +case class BottomUp() extends GenerationOption { + def name:String = "bottomUp" +} + +trait Utility { + val paradigm: AnyParadigm + val names: NameProvider[paradigm.syntax.Name] + val ooParadigm: ObjectOriented.WithBase[paradigm.type] + val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext, paradigm.type] + val arithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val realArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] + val array: Arrays.WithBase[paradigm.MethodBodyContext, paradigm.type] + val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] + val strings: Strings.WithBase[paradigm.MethodBodyContext, paradigm.type] + val booleans: Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] + + import ooParadigm.* + import paradigm.* + import syntax.* + + // known to ALL approaches (top-down or bottom up) + lazy val helperName = names.mangle("helper") + lazy val computeName = names.mangle("compute") + lazy val retrieveName = names.mangle("retrieve") + + class DPExample[Input, Output, Full_Solution] (val name:String, val example:Input, val solution:Output, val full_solution:Full_Solution) { + } + + def hostType(tpe:ArgumentType) : TypeRep = { + tpe match { + case IntegerType() => TypeRep.Int + case StringType() => TypeRep.String + case CharType() => TypeRep.Char + case BooleanType() => TypeRep.Boolean + + case _ => ??? + } + } + + def pair_helper(): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + + for { + + //Setting up header + argType <- toTargetLanguageType(TypeRep.Int) + argName1 = names.mangle("i") + argName2 = names.mangle("j") + + _ <- setParameters(Seq((argName1,argType),(argName2,argType))) + + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) + + //Function details + args <- getArguments() + i = args.head._3 + j = args.tail.head._3 + + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + two <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + + ipj <- arithmetic.arithmeticCapabilities.add(i, j) + ipjp1 <- arithmetic.arithmeticCapabilities.add(ipj, one) + + ipjtipjp1 <- arithmetic.arithmeticCapabilities.mult(ipj, ipjp1) + + ipjtipjp1o2 <- arithmetic.arithmeticCapabilities.div(ipjtipjp1, two) + + finalExpression <- arithmetic.arithmeticCapabilities.add(ipjtipjp1o2, i) + + + } yield Some(finalExpression) + } + + + def generate_DP_int_array_test[FS](clazz:Name, tests:Seq[DPExample[Seq[Int],Int,FS]]): Generator[MethodBodyContext, Seq[Expression]] = { + import AnyParadigm.syntax.* + import eqls.equalityCapabilities.* + import paradigm.methodBodyCapabilities.* + for { + solutionType <- ooParadigm.methodBodyCapabilities.findClass(clazz) + sol <- ooParadigm.methodBodyCapabilities.instantiateObject(solutionType, Seq.empty, None) + computeMethod <- ooParadigm.methodBodyCapabilities.getMember(sol, names.mangle("compute")) + arrayType <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + + assert_statements <- forEach(tests) { example => + for { + expr <- create_int_array(example.example) + variable <- impParadigm.imperativeCapabilities.declareVar(names.mangle(example.name), arrayType, Some(expr)) + invoke <- apply(computeMethod, Seq(variable)) + solution <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, example.solution) + assert_stmt <- asserts.assertionCapabilities.assertEquals(arrayType, invoke, solution) + } yield assert_stmt + } + } yield assert_statements + } + + @deprecated(message = "Initial attempt at generating code to retrieve solution. Doesn't yet work.") + def generate_retrieve(model: Model): Generator[paradigm.MethodBodyContext, Option[Expression]] = { + import paradigm.methodBodyCapabilities.* + + val label: String = model.retrieveLabel + + for { + intType <- toTargetLanguageType(TypeRep.Int) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + + params = model.bounds.foldLeft(Seq.empty[(Name, Type)]) { (acc, bound) => + acc :+ (names.mangle(bound.itArgName), intType) + } + + _ <- setParameters(params) + _ <- setReturnType(intType) + +// ivar_outer <- impParadigm.imperativeCapabilities.declareVar(names.mangle(model.bounds.head.itArgName), intType, Some(zero)) + +// ijk <- model.bounds.foldLeft(Seq.empty[Expression]) { (acc, bound) => +// acc :+ +// } + + self <- ooParadigm.methodBodyCapabilities.selfReference() + recursive_call <- ooParadigm.methodBodyCapabilities.getMember(self, retrieveName) +// application <- paradigm.methodBodyCapabilities.apply(recursive_call, ijk) + + } yield Some(recursive_call) + } + + // NOTE: I can make generic with CONTEXT but can't remember syntax. + def map_type_in_class(argType: ArgumentType) : Generator[ooParadigm.ClassContext, Type] = { + import ooParadigm.classCapabilities.* + import org.combinators.models.* + + argType match { + case _:IntegerType => for { + tpe <- toTargetLanguageType(TypeRep.Int) + } yield tpe + + case _:CharType => for { + tpe <- toTargetLanguageType(TypeRep.Char) + } yield tpe + + case _:BooleanType => for { + tpe <- toTargetLanguageType(TypeRep.Boolean) + } yield tpe + + case _:StringType => for { + tpe <- toTargetLanguageType(TypeRep.String) + } yield tpe + + case _:IntegerArrayType => for { + tpe <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + } yield tpe + + case _:IntegerArray2DType => for { + tpe <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + } yield tpe + + case _:StringArrayType => for { + tpe <- toTargetLanguageType(TypeRep.Array(TypeRep.String)) + } yield tpe + + + // find which ones need to be implemented + case _ => ??? + } + } + + def max_bound_in_method(argExpr: ArgExpression) : Generator[paradigm.MethodBodyContext, Expression] = { + import org.combinators.models.* + + argExpr.argType match { + case _:IntegerType => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(argExpr.name)) + } yield field + + case _:BooleanType => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(argExpr.name)) + } yield field + + case _:StringType => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(argExpr.name)) + lengthMethod <- ooParadigm.methodBodyCapabilities.getMember(field, names.mangle("length")) // a bit of a hack for string + invoke <- paradigm.methodBodyCapabilities.apply(lengthMethod, Seq.empty) + } yield invoke + + case _:IntegerArrayType => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(argExpr.name)) + lengthField <- ooParadigm.methodBodyCapabilities.getMember(field, names.mangle("length")) // a bit of a hack for string + } yield lengthField + + case _:IntegerArray2DType => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(argExpr.name)) + lengthField <- ooParadigm.methodBodyCapabilities.getMember(field, names.mangle("length")) // a bit of a hack for string + } yield lengthField + + // find which ones need to be implemented + case _ => ??? + } + } + + def map_type_in_method(argType: ArgumentType) : Generator[paradigm.MethodBodyContext, Type] = { + import org.combinators.models.* + import paradigm.methodBodyCapabilities.* + + argType match { + case _:IntegerType => for { + tpe <- toTargetLanguageType(TypeRep.Int) + } yield tpe + + case _:BooleanType => for { + tpe <- toTargetLanguageType(TypeRep.Int) + } yield tpe + + case _:CharType => for { + tpe <- toTargetLanguageType(TypeRep.Char) + } yield tpe + + case _:StringType => for { + tpe <- toTargetLanguageType(TypeRep.String) + } yield tpe + + // find which ones need to be implemented + case _ => ??? + } + } + + /** + * Creates function using parameters from model and returns int: + * + * int SOMEFUNCTION (ARGS) + * + * where ARGS represents the model (i.e., (("n", Int)) for Fibonacci and (("s1", String), ("s2", String)) for LCS + */ + def make_helper_method_signature(args:Seq[ArgExpression]): Generator[paradigm.MethodBodyContext, Unit] = { + import paradigm.methodBodyCapabilities.* + + // Type of helper method param is always an integer to refer to earlier subproblem + // + + for { + params <- forEach(args) { arg => for { + argType <- toTargetLanguageType(TypeRep.Int) // Always will be int since subproblems are ordered + argName = names.mangle(arg.itArgName) // use pre-selected iterator + } yield (argName, argType) + } + _ <- setParameters(params) + + intType <- toTargetLanguageType(TypeRep.Int) + _ <- setReturnType(intType) // should always be int, but could be stored in Model + } yield None + } + + + /** + * Institute plan for mutual recursion of helper(args) method which calls memo(args) on smaller subproblem, and that + * method is responsible for computing and storing these subproblems. + * + * For Bottom-up solutions, there needs to be a way to access the state storing the previous computations. This is in bottomUp:Option[Expression] + * + * As code is generated, there needs to be a way to access information, and that is placed in symbolTable, which maps string (like variable name) to + * the variable expression (either an argument to the parameter or a locally defined variable). + * + * The reason for the map is that there is NO WAY to get the reference to a local variable within coGen; perhaps this lack of capability is for the best + * since it might otherwise generate code that cannot compile. + * + */ + def explore(expr : org.combinators.models.Expression, memoize:Boolean = true, symbolTable: Map[String,Expression], bottomUp:Option[Expression] = None) : Generator[paradigm.MethodBodyContext, Expression] = { + + // turn model Expression into a real expression + expr match { + case self:SelfExpression => for { + neg92 <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -92) + debugvar <- paradigm.methodBodyCapabilities.reify(TypeRep.String, self.variableName) + e = symbolTable(self.variableName) + } yield e + + case eq: EqualExpression => for { + eq_tpe <- map_type_in_method(eq.argType) // was just .tpe before + left <- explore(eq.left, memoize, symbolTable, bottomUp) + right <- explore(eq.right, memoize, symbolTable, bottomUp) + + e <- eqls.equalityCapabilities.areEqual(eq_tpe, left, right) + } yield e + + case eq: LessThanExpression => for { + left <- explore(eq.left, memoize, symbolTable, bottomUp) + right <- explore(eq.right, memoize, symbolTable, bottomUp) + e <- arithmetic.arithmeticCapabilities.lt(left, right) + } yield e + + case eq: LessThanOrEqualExpression => for { + left <- explore(eq.left, memoize, symbolTable, bottomUp) + right <- explore(eq.right, memoize, symbolTable, bottomUp) + e <- arithmetic.arithmeticCapabilities.le(left, right) + } yield e + + case or:OrExpression => for { + left <- explore(or.left, memoize, symbolTable, bottomUp) + right <- explore(or.right, memoize, symbolTable, bottomUp) + e <- booleans.booleanCapabilities.or(Seq(left, right)) + } yield e + + case or:AndExpression => for { + left <- explore(or.left, memoize, symbolTable, bottomUp) + right <- explore(or.right, memoize, symbolTable, bottomUp) + e <- booleans.booleanCapabilities.and(Seq(left, right)) + } yield e + + case mx:MaxExpression => for { + left <- explore(mx.left, memoize, symbolTable, bottomUp) + right <- explore(mx.right, memoize, symbolTable, bottomUp) + e <- realArithmetic.realArithmeticCapabilities.max(left, right) + } yield e + + case mn:MinExpression => for { + left <- explore(mn.left, memoize, symbolTable, bottomUp) + right <- explore(mn.right, memoize, symbolTable, bottomUp) + e <- realArithmetic.realArithmeticCapabilities.min(left, right) + } yield e + + // takes "text1" and returns "this.text1" + case ie:InputExpression => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + e <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(ie.variableName)) + } yield e + + // StringLengthExpression(ArgExpression(0)), n)) + case sle:StringLengthExpression => for { + inner <- explore(sle.string, memoize, symbolTable, bottomUp) + e <- strings.stringCapabilities.getStringLength(inner) + } yield e + + case sub:SubStringExpression => for { + inner <- explore(sub.string, memoize, symbolTable, bottomUp) + start <- explore(sub.start, memoize, symbolTable, bottomUp) + exclusiveEnd <- explore(sub.exclusiveEnd, memoize, symbolTable, bottomUp) + e <- strings.stringCapabilities.subString(inner, start, exclusiveEnd) + } yield e + + case cae:CharAtExpression => for { + inner <- explore(cae.string, memoize, symbolTable, bottomUp) + idx <- explore(cae.index, memoize, symbolTable, bottomUp) + e <- strings.stringCapabilities.getCharAt(inner, idx) + } yield e + + case ae: SubtractionExpression => for { + left <- explore(ae.left, memoize, symbolTable, bottomUp) + right <- explore(ae.right, memoize, symbolTable, bottomUp) + e <- arithmetic.arithmeticCapabilities.sub(left, right) + } yield e + + case ae: AdditionExpression => for { + left <- explore(ae.left, memoize, symbolTable, bottomUp) + right <- explore(ae.right, memoize, symbolTable, bottomUp) + e <- arithmetic.arithmeticCapabilities.add(left, right) + } yield e + + case arge:ArgExpression => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + field <- ooParadigm.methodBodyCapabilities.getMember(self, names.mangle(arge.name)) + } yield field + + case alen:ArrayLengthExpression => for { + inner <- explore(alen.array, memoize, symbolTable, bottomUp) + len <- ooParadigm.methodBodyCapabilities.getMember(inner, names.mangle("length")) + } yield len + + case arr:ArrayElementExpression => for { + // Access array[idx] value + inner <- explore(arr.array, memoize, symbolTable, bottomUp) + idx <- explore(arr.index, memoize, symbolTable, bottomUp) + e <- array.arrayCapabilities.get(inner, Seq(idx)) + } yield e + + case me:MultiplicationExpression => for { + left <- explore(me.left, memoize, symbolTable, bottomUp) + right <- explore(me.right, memoize, symbolTable, bottomUp) + e <- arithmetic.arithmeticCapabilities.mult(left, right) + } yield e + + case ter:TernaryExpression => for { + resultName <- paradigm.methodBodyCapabilities.freshName(names.mangle("result")) + resultType <- paradigm.methodBodyCapabilities.toTargetLanguageType(hostType(ter.trueBranch.tpe)) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + resultVar <- impParadigm.imperativeCapabilities.declareVar(resultName, resultType, Some(zero)) + + cond <- explore(ter.condition, memoize, symbolTable, bottomUp) + + ifThenElse <- impParadigm.imperativeCapabilities.ifThenElse(cond, for { + trueBranch <- explore(ter.trueBranch, memoize, symbolTable, bottomUp) + trueAssign <- impParadigm.imperativeCapabilities.assignVar(resultVar, trueBranch) + _ <- paradigm.methodBodyCapabilities.addBlockDefinitions(Seq(trueAssign)) + } yield (), Seq.empty, Some(for { + falseBranch <- explore(ter.falseBranch, memoize, symbolTable, bottomUp) + falseAssign <- impParadigm.imperativeCapabilities.assignVar(resultVar, falseBranch) + _ <- paradigm.methodBodyCapabilities.addBlockDefinitions(Seq(falseAssign)) + } yield ())) + + _ <- paradigm.methodBodyCapabilities.addBlockDefinitions(Seq(ifThenElse)) + } yield resultVar + + case se: SubproblemExpression => for { + self <- ooParadigm.methodBodyCapabilities.selfReference() + + // THIS could be turned into a decorator so we don't have to embed here the memo vs. helper concept another day + f <- if (memoize) { + ooParadigm.methodBodyCapabilities.getMember(self, names.mangle("memo")) + } else { + ooParadigm.methodBodyCapabilities.getMember(self, names.mangle("helper")) + } + + all_exprs <- forEach(se.args) { expr => for { + exp <- explore(expr, memoize, symbolTable, bottomUp) + } yield exp + } + + res <- if (!bottomUp.isEmpty) { + get_matrix_element(bottomUp.get, all_exprs) + } else { + paradigm.methodBodyCapabilities.apply(f, all_exprs) + } + + } yield res + + case hp:HelperExpression => + Command.lift(symbolTable(hp.variable)) + + case it:IteratorExpression => for { + actual <- if (bottomUp.isDefined) { + for { + args <- paradigm.methodBodyCapabilities.getArguments() // HACK: needed to start the for lop off. + e = symbolTable(it.variable) + } yield e + } else { + for { + args <- paradigm.methodBodyCapabilities.getArguments() + } yield args(it.iteratorNumber)._3 + } + } yield actual + + case lit:LiteralInt => for { + actual <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, lit.literal) + } yield actual + + case bool:LiteralBoolean => for { + actual <- paradigm.methodBodyCapabilities.reify(TypeRep.Boolean, bool.literal) + } yield actual + + case char:LiteralChar => for { + actual <- paradigm.methodBodyCapabilities.reify(TypeRep.Char, char.literal) + } yield actual + + case _ => for { // PLACEHOLDER FOR EVERYTHING ELSE + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, -99) + } yield zero + } + } + + def create_string_array(values:Seq[String]) : Generator[MethodBodyContext, Expression] = { + import paradigm.methodBodyCapabilities.canReifyInMethodBody // needed for implicit arg to create + for { + translated_vals <- forEach(values) { value => + for { + reified_value <- paradigm.methodBodyCapabilities.reify(TypeRep.String, value) + } yield reified_value + } + + stringType <- paradigm.methodBodyCapabilities.toTargetLanguageType(TypeRep.String) + result <- array.arrayCapabilities.create(stringType, Seq(1), translated_vals) + } yield result + } + + def create_int_array(values:Seq[Int]) : Generator[MethodBodyContext, Expression] = { + import paradigm.methodBodyCapabilities.canReifyInMethodBody // needed for implicit arg to create + for { + translated_vals <- forEach(values) { value => + for { + reified_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, value) + } yield reified_value + } + + intType <- paradigm.methodBodyCapabilities.toTargetLanguageType(TypeRep.Int) + result <- array.arrayCapabilities.create(intType, Seq(1), translated_vals) + } yield result + } + + def create_int_nd_array(values:Seq[Int], dimensions:Seq[Int]) : Generator[MethodBodyContext, Expression] = { + import paradigm.methodBodyCapabilities.canReifyInMethodBody // needed for implicit arg to create + for { + translated_vals <- forEach(values) { value => + for { + reified_value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, value) + } yield reified_value + } + + intType <- paradigm.methodBodyCapabilities.toTargetLanguageType(TypeRep.Int) + result <- array.arrayCapabilities.create(intType, dimensions, translated_vals) + } yield result + } + + @deprecated("replace with create_array") + def set_array(sampleVar: Expression, index:Int, values:Seq[Int]) : Generator[MethodBodyContext, Seq[Statement]] = { + if (values.length == 1) { + // last one + for { + d_i <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, index) + d_v <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, values.head) + varIndex <- array.arrayCapabilities.get(sampleVar, Seq(d_i)) + a_i <- impParadigm.imperativeCapabilities.assignVar(varIndex, d_v) + } yield Seq(a_i) + } else { + // recursively + for { + d_i <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, index) + d_v <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, values.head) + varIndex <- array.arrayCapabilities.get(sampleVar, Seq(d_i)) + a_i <- impParadigm.imperativeCapabilities.assignVar(varIndex, d_v) + all_seq <- set_array(sampleVar, index+1, values.tail) + } yield all_seq :+ a_i + } + } + + /** + * Helper for max operations, represents 'm=max(m,r)' + * Returns the generated max statement + */ + def set_max(maxVar: Expression, replacement: Expression): Generator[MethodBodyContext, Statement] = { + import paradigm.methodBodyCapabilities.* + for { + maxCond <- arithmetic.arithmeticCapabilities.lt(maxVar, replacement) + maxIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(maxCond, for { + + assignStmt <- impParadigm.imperativeCapabilities.assignVar(maxVar, replacement) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty + ) + } yield maxIfStmt + } + + //This code does not work, can't access static method on class + def full_set_max(maxVar: Expression, e1: Expression, e2: Expression): Generator[MethodBodyContext, Statement] = { + import ooParadigm.methodBodyCapabilities.* + import paradigm.methodBodyCapabilities.* + for { + mathClass <- findClass(names.mangle("Math")) + instantiated <- ooParadigm.methodBodyCapabilities.instantiateObject(mathClass, Seq.empty, None) + method <- getMember(instantiated, names.mangle("max")) + maxExp <- apply(method, Seq(e1, e2)) + maxStmt <- impParadigm.imperativeCapabilities.assignVar(maxVar, maxExp) + } yield (maxStmt) + } + + def new_full_set_max(maxVar: Expression, e1: Expression, e2: Expression): Generator[MethodBodyContext, Seq[Statement]] = { + import paradigm.methodBodyCapabilities.* + + for { + set1 <- impParadigm.imperativeCapabilities.assignVar(maxVar, e1) + + intType <- toTargetLanguageType(TypeRep.Int) + tempName <- freshName(names.mangle("temp")) + zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) + tempVar <- impParadigm.imperativeCapabilities.declareVar(tempName, intType, Some(zero)) + tempAssign <- impParadigm.imperativeCapabilities.assignVar(tempVar, e2) + + maxCond <- arithmetic.arithmeticCapabilities.lt(maxVar, tempVar) + maxIfStmt <- impParadigm.imperativeCapabilities.ifThenElse(maxCond, for { + assignStmt <- impParadigm.imperativeCapabilities.assignVar(maxVar, tempVar) + _ <- addBlockDefinitions(Seq(assignStmt)) + } yield (), + Seq.empty + ) + } yield Seq(set1, tempAssign, maxIfStmt) + } + + def plus_equals(variable: Expression, value: Expression): Generator[MethodBodyContext, Statement] = { + for { + addExpr <- arithmetic.arithmeticCapabilities.add(variable, value) + assign <- impParadigm.imperativeCapabilities.assignVar(variable, addExpr) + } yield assign + } + + def char_at(string: Expression, index: Expression): Generator[MethodBodyContext, Expression] = { + import ooParadigm.methodBodyCapabilities.* + import paradigm.methodBodyCapabilities.* + + for { + method <- getMember(string, names.mangle("charAt")) + char_at <- apply(method, Seq(index)) + } yield char_at + } + + def declare_and_inst_variable(varName: String, varType: Type, varValueGenerator: Generator[paradigm.MethodBodyContext, Expression]): Generator[paradigm.MethodBodyContext, Expression] = { + for { + varValue <- varValueGenerator + outputVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(varName), varType, Some(varValue)) + } yield outputVar + } + + def declare_and_inst_variable(varName: String, varType: Type, varValue: Expression): Generator[paradigm.MethodBodyContext, Expression] = { + for { + outputVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle(varName), varType, Some(varValue)) + } yield outputVar + } + + def make_for_loop(iterator: Expression, guard: Expression, update: Expression, body: Seq[Statement]): Generator[paradigm.MethodBodyContext, Statement] = { + import paradigm.methodBodyCapabilities.* + + for { + while_loop <- impParadigm.imperativeCapabilities.whileLoop( + guard, + for { + _ <- addBlockDefinitions(body) + updated_iterator <- impParadigm.imperativeCapabilities.assignVar(iterator, update) + _ <- addBlockDefinitions(Seq(updated_iterator)) + } yield () + ) + } yield while_loop + } + + def make_for_loop(iterator: Expression, guard: Expression, body: Seq[Statement]): Generator[paradigm.MethodBodyContext, Statement] = { + import paradigm.methodBodyCapabilities.* + + for { + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + + while_loop <- impParadigm.imperativeCapabilities.whileLoop(guard, for { + _ <- addBlockDefinitions(body) + + incrExpr <- arithmetic.arithmeticCapabilities.add(iterator, one) + incrStmt <- impParadigm.imperativeCapabilities.assignVar(iterator, incrExpr) + _ <- addBlockDefinitions(Seq(incrStmt)) + } yield ()) + + //_ <- addBlockDefinitions(Seq(while_loop)) + + } yield while_loop + } + + def get_matrix_element(matrix: Expression, indices:Seq[Expression]): Generator[paradigm.MethodBodyContext, Expression] = { + + for { + ai <- array.arrayCapabilities.get(matrix, indices) + } yield ai + +// println("get_matrix_element might have simpler implementation with new n-dimensional array get") +// +// if (indices.length == 1) { +// for { +// ai <- array.arrayCapabilities.get(matrix, Seq(indices.head)) +// } yield ai +// } else if (indices.length == 2) { +// for { +// ai <- array.arrayCapabilities.get(matrix, Seq(indices.head)) +// aij <- array.arrayCapabilities.get(ai, Seq(indices.tail.head)) +// } yield aij +// } else if (indices.length == 3) { +// for { +// ai <- array.arrayCapabilities.get(matrix, Seq(indices.head)) +// aij <- array.arrayCapabilities.get(ai, Seq(indices.tail.head)) +// aijk <- array.arrayCapabilities.get(aij, Seq(indices.tail.tail.head)) +// } yield aijk +// } else if (indices.length == 3) { +// for { +// ai <- array.arrayCapabilities.get(matrix, Seq(indices.head)) +// aij <- array.arrayCapabilities.get(ai, Seq(indices.tail.head)) +// aijk <- array.arrayCapabilities.get(aij, Seq(indices.tail.tail.head)) +// aijkl <- array.arrayCapabilities.get(aij, Seq(indices.tail.tail.tail.head)) +// } yield aijkl +// } else { +// ??? +// } + } + + def get_matrix_element(matrix: Expression, row: Expression, col: Expression): Generator[paradigm.MethodBodyContext, Expression] = { + println("get_matrix_element might have simpler implementation now with n-d arrays") + for { + matrix_at_r <- array.arrayCapabilities.get(matrix, Seq(row)) + matrix_at_r_c <- array.arrayCapabilities.get(matrix_at_r, Seq(col)) + } yield matrix_at_r_c + } + + /** + * Helper function for nested for loops. + * + * @param var1 An expression representing the variable to be updated in the outer loop. + * @param guard1 An expression representing the guard condition for the outer loop. + * @param update1 An expression representing the update expression for the outer loop. + * @param var2 An expression representing the variable to be updated in the inner loop. + * @param guard2 An expression representing the guard condition for the inner loop. + * @param update2 An expression representing the update expression for the inner loop. + * @param inner_body The body of the inner loop. + * @param trailing_body Additional statements to be executed at the end of the inner loop after the execution of the inner loop. + * @return A generator of statements for the outer loop. + */ + def make_nested_for_loop(var1: Expression, guard1: Expression, update1: Expression, + var2: Expression, guard2: Expression, update2: Expression, + inner_body: Seq[Statement], trailing_body: Seq[Statement]): Generator[paradigm.MethodBodyContext, Statement] = { + import paradigm.methodBodyCapabilities.* + + for { + outer_loop <- impParadigm.imperativeCapabilities.whileLoop(guard1, + for { + inner_loop <- impParadigm.imperativeCapabilities.whileLoop(guard2, + for { + _ <- addBlockDefinitions(inner_body) + + updateStmt <- impParadigm.imperativeCapabilities.assignVar(var2, update2) + _ <- addBlockDefinitions(Seq(updateStmt)) + } yield () + ) + + _ <- addBlockDefinitions(Seq(inner_loop)) + + _ <- addBlockDefinitions(trailing_body) + + updateStmt <- impParadigm.imperativeCapabilities.assignVar(var1, update1) + _ <- addBlockDefinitions(Seq(updateStmt)) + } yield () + ) + } yield outer_loop + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/Expression.scala b/dynamicProgramming/src/main/scala/org/combinators/models/Expression.scala new file mode 100644 index 00000000..3cd598d9 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/Expression.scala @@ -0,0 +1,201 @@ +package org.combinators.models + +// Nice use of overloading to simplify the expressions +trait Expression { + def +(other: Expression): Expression = AdditionExpression(this, other) + def -(other: Expression): Expression = SubtractionExpression(this, other) + def *(other: Expression): Expression = MultiplicationExpression(this, other) + def /(other: Expression): Expression = DivisionExpression(this, other) + + def <(other: Expression): Expression & BooleanExpression = LessThanExpression(this, other) + def <=(other: Expression): Expression & BooleanExpression = LessThanOrEqualExpression(this, other) + def >(other: Expression) : Expression & BooleanExpression = LessThanExpression(other, this) // opposite + def >=(other: Expression) : Expression & BooleanExpression = LessThanOrEqualExpression(other, this) // opposite + + // When using ==, must assume it is IntegerType: Dangerous?? todo: allow for other types(?) + def ==(other: Expression): Expression & BooleanExpression = EqualExpression(this, other, IntegerType()) + def ||(other: Expression): Expression & BooleanExpression = OrExpression(this, other) + def &&(other: Expression): Expression & BooleanExpression = AndExpression(this, other) + + def apply(other: Expression): Expression = ArrayElementExpression(this, other) + def tpe:ArgumentType +} + +// tagging an expression as returning a Boolean value, which means it can be used in IfElseExpression +trait BooleanExpression { + def tpe:ArgumentType = BooleanType() +} + +/** + * Necessary for defining what will be either Input or Output of a test case + * + */ +trait LiteralExpression + +class UnitExpression extends LiteralExpression { + def tpe: ArgumentType = UnitType() +} // VOID + +//Integer +case class AdditionExpression(left: Expression, right: Expression) extends Expression { + def tpe: ArgumentType = { + val leftType = left.tpe + val rightType = right.tpe + assert (leftType == rightType, "Mismatched types in Expression") + leftType + } +} +case class SubtractionExpression(left: Expression, right: Expression) extends Expression { + def tpe: ArgumentType = { + val leftType = left.tpe + val rightType = right.tpe + assert (leftType == rightType, "Mismatched types in Expression") + leftType + } +} +case class MultiplicationExpression(left: Expression, right: Expression) extends Expression { + def tpe: ArgumentType = { + val leftType = left.tpe + val rightType = right.tpe + assert (leftType == rightType, "Mismatched types in Expression") + leftType + } +} +case class DivisionExpression(left: Expression, right: Expression) extends Expression { + def tpe: ArgumentType = { + val leftType = left.tpe + val rightType = right.tpe + assert (leftType == rightType, "Mismatched types in Expression") + leftType + } +} + +// Vast majority are IntegerType +case class SubproblemExpression(args: Seq[Expression], argType:ArgumentType = IntegerType()) extends Expression { + def tpe: ArgumentType = argType +} + +// If helper is defined but NOT part of the parameters during invocation, then it must be passed in as helpers +case class SubproblemInvocation( + order:Seq[String], + helpers:Map[String,HelperExpression] = Map.empty, // known variables that are used in the problem expansion without being iterated over or called + returnType: ArgumentType = IntegerType(), + mappers: Map[String, Expression] = Map.empty) // variables that map to new coordinates into dp[] space and are added to bottom up + +case class MaxExpression(left: Expression, right: Expression) extends Expression { + def tpe: ArgumentType = { + val leftType = left.tpe + val rightType = right.tpe + assert (leftType == rightType, "Mismatched types in Expression") + leftType + } +} +case class MinExpression(left: Expression, right: Expression) extends Expression { + def tpe: ArgumentType = { + val leftType = left.tpe + val rightType = right.tpe + assert (leftType == rightType, "Mismatched types in Expression") + leftType + } +} + +case class ArrayElementExpression(array: Expression, index: Expression) extends Expression { + def tpe:ArgumentType = { + assert(array.tpe.isInstanceOf[org.combinators.models.ArrayType], "ArrayElementExpression needs an array as first argument.") + array.tpe.asInstanceOf[org.combinators.models.ArrayType].elementType + } +} + +// TODO: Unused though could be used in future +case class FunctionExpression(name:String, args: Seq[Expression]) extends Expression { + def tpe:ArgumentType = IntegerType() +} + +case class LiteralInt(literal: Int) extends LiteralExpression with Expression { + def tpe:ArgumentType = IntegerType() +} +case class IteratorExpression(iteratorNumber: Int, variable:String) extends Expression { + def tpe: ArgumentType = IntegerType() +} + +case class CharToAsciiExpression(char: Expression) extends Expression { + def tpe:ArgumentType = IntegerType() +} + +// low and high are INCLUSIVE +case class HelperExpression(variable:String, + low:Expression, + in_range:Expression, + high:Expression) extends Expression { + def tpe:ArgumentType = IntegerType() +} + +case class PackedArrayType(elementType:ArgumentType) extends ArgumentType + +/** This remains a class (not case class) because of the auxiliary constructor (to play nice with IntelliJ editor) */ +class LiteralArray(val literal:Array[Int], val dimensions:Seq[Int]) extends LiteralExpression { + + // Auxiliary constructor to handle situation where dimensions is not provided: Just defaults to a one-dimension array of given length. + def this(literal:Array[Int]) = { + this(literal, Seq(literal.length)) + } + + def tpe:ArgumentType = PackedArrayType(IntegerType()) +} + +// For when a HelpExpression needs to refer to self +// TODO: pass in +case class SelfExpression(variableName:String) extends Expression { + def tpe:ArgumentType = ??? +} + +case class StringLengthExpression(string: Expression) extends Expression { + def tpe:ArgumentType = IntegerType() +} +case class SubStringExpression(string:Expression, start:Expression, exclusiveEnd:Expression) extends Expression { + def tpe:ArgumentType = StringType() +} +case class ArrayLengthExpression(array: Expression) extends Expression { + def tpe:ArgumentType = IntegerType() +} + +//String +case class LiteralString(literal: String) extends LiteralExpression { + def tpe:ArgumentType = StringType() +} + +//Character +case class LiteralChar(literal:Char) extends LiteralExpression with Expression { + def tpe:ArgumentType = CharType() +} +case class CharAtExpression(string: Expression, index: Expression) extends Expression { + def tpe:ArgumentType = CharType() +} + +// Access field access for the primary class +// TODO: OLD and deal with later +case class InputExpression(variableName:String) extends Expression { + def tpe:ArgumentType = ??? +} + +case class EqualExpression(left: Expression, right: Expression, argType:ArgumentType = org.combinators.models.IntegerType()) extends Expression with BooleanExpression +case class OrExpression(left: Expression, right: Expression) extends Expression with BooleanExpression +case class AndExpression(left: Expression, right: Expression) extends Expression with BooleanExpression +case class LessThanExpression(left: Expression, right:Expression) extends Expression with BooleanExpression +case class LessThanOrEqualExpression(left: Expression, right:Expression) extends Expression with BooleanExpression +case class TernaryExpression(condition: Expression & BooleanExpression, trueBranch: Expression, falseBranch: Expression) extends Expression { + def tpe:ArgumentType = { + val trueType = trueBranch.tpe + val falseType = falseBranch.tpe + assert(trueType == falseType, "Mismatched types in TernaryExpression") + trueType + } +} + +case class LiteralBoolean(literal:Boolean) extends LiteralExpression with Expression with BooleanExpression + +// Now includes the name of the int variable to iterate over +case class ArgExpression(whichArg: Int, name:String, argType:ArgumentType, itArgName:String) extends Expression { + def tpe:ArgumentType = argType +} + diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/Glossary.scala b/dynamicProgramming/src/main/scala/org/combinators/models/Glossary.scala new file mode 100644 index 00000000..b11c5fa9 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/Glossary.scala @@ -0,0 +1,164 @@ +package org.combinators.models + +/** + * sbt "dp/runMain org.combinators.modelTests.Glossary [bottomUp | topDown | topDownMemo]" + * + * Creates output files in target/bottomUp or target\topDown or target\topDownMemo + */ + +import cats.effect.{ExitCode, IO, IOApp} +import org.apache.commons.io.FileUtils +import org.combinators.archive.cogen.bottomUp.twoSequences.longestCommonSubsequence.LCSMainJava +import org.combinators.archive.unenhancedModels.boilerplate.uncrossedLines.UnenhancedUncrossedLinesMainJava +import org.combinators.archive.unenhancedModels.models.twoSequences.{LongestCommonSubsequenceModel, UncrossedLinesModel} +import org.combinators.dp.enhanced.EnhancedMainInterface +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.boilerplate.grid.{CountSquaresMainJava, MinPathSumMainJava, UniquePathsMainJava} +import org.combinators.boilerplate.integer.{BellNumberMainJava, DiceThrowMainJava, FibonacciMainJava, PerfectSquaresMainJava, TribonacciMainJava} +import org.combinators.boilerplate.oneSequence.{MatrixChainMultiplicationBottomUpMainJava, MatrixChainMultiplicationTopDownMainJava, MinCostClimbingStairMainJava} +import org.combinators.boilerplate.strings.{InterleaveStringsMainJava, ThreeStringsLCSMainJava} +import org.combinators.boilerplate.twoSequences.{LongestCommonSubsequenceMainJava, UncrossedLinesMainJava} +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} + +import java.nio.file.{Path, Paths} +import scala.collection.Seq + +class Glossary { + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, files: Seq[FileWithPath]): IO[Unit] = { + IO { + print("Computing Files...") + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path,files: Seq[FileWithPath]): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, files) + } yield ExitCode.Success + } +} + +object GlossaryToDiskMain extends IOApp { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + // declare the working versions for each problem in the enhanced list + val known_enhanced_solutions:Seq[(EnhancedMainInterface, Seq[GenerationOption])] = Seq( + (new BellNumberMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new CountSquaresMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new DiceThrowMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new FibonacciMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new InterleaveStringsMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new LongestCommonSubsequenceMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new MinCostClimbingStairMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new PerfectSquaresMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new ThreeStringsLCSMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new UncrossedLinesMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), +// (new NeedlemanWunschSequenceAlignmentMainJava(), NeedlemanWunschSequenceAlignmentToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), +// (new DistinctSubsequencesMainJava(), DistinctSubsequencesToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), +// (new WildcardPatternMatchingMainJava(), WildcardPatternMatchingToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), +// (new ShortestCommonSupersequenceMainJava(), ShortestCommonSupersequenceToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), + (new TribonacciMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new UniquePathsMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + (new MinPathSumMainJava(), Seq(topDown, topDownWithMemo, bottomUp)), + + // generates but has flawed logic because of the transformation of (r,c) into (i,j) + // CHALLENGING (new MatrixChainMultiplicationMainJava(), MatrixChainMultiplicationMainDirectToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), + ) + + // below are the individual DP problems generated and added to `all_files`. + def top_down_memo_files(): Seq[FileWithPath] = { + + // UncrossedLinesMainJava and LCSMainJava still don't work + + val mcm_td = (new MatrixChainMultiplicationTopDownMainJava(), Seq(topDown, topDownWithMemo)) + val just_td = Seq(mcm_td) + + val others = (just_td ++ known_enhanced_solutions).filter(pair + => pair._2.contains(TopDown(memo = true))). + flatMap(pair => pair._1.filesToGenerate(TopDown(memo = true))) + + others + } + + // below are the individual DP problems generated and added to `all_files`. + def top_down(): Seq[FileWithPath] = { +// val ul = new UncrossedLinesMainJava().filesToGenerate(new UncrossedLinesModel().instantiate(), TopDown()) + //val lcs = new LCSMainJava().filesToGenerate(new LongestCommonSubsequenceModel().instantiate(), TopDown()) [HEINEMAN: not working] + // val kp = new KnapsackMainJava().filesToGenerate(new KnapsackModel().instantiate(), TopDown()) [HEINEMAN: not working] + //val nwsa = new NWSAMainJava().filesToGenerate(new NeedlemanWunschSequenceAlignmentModel().instantiate(), TopDown()) [HEINEMAN: not working] + + val mcm_td = (new MatrixChainMultiplicationTopDownMainJava(), Seq(topDown, topDownWithMemo)) + val just_td = Seq(mcm_td) + + val others = (just_td ++ known_enhanced_solutions).filter(pair + => pair._2.contains(TopDown())) + .flatMap(pair => pair._1.filesToGenerate(TopDown())) + + others + } + + def bottom_up_files() : Seq[FileWithPath] = { + val ul = new UnenhancedUncrossedLinesMainJava().filesToGenerate(new UncrossedLinesModel().instantiate(), BottomUp()) + val lcs = new LCSMainJava().filesToGenerate(new LongestCommonSubsequenceModel().instantiate(), BottomUp()) + + val mcm_bot = (new MatrixChainMultiplicationBottomUpMainJava(), Seq(bottomUp)) + val just_bot = Seq(mcm_bot) + + val others = (just_bot ++ known_enhanced_solutions).filter(pair + => pair._2.contains(BottomUp())) + .flatMap(pair => pair._1.filesToGenerate(BottomUp())) + others + } + + def run(args: List[String]): IO[ExitCode] = { + val choice = if (args.isEmpty) { + topDownWithMemo // <------ CHANGE this manually when you run, to generate topDown or topDownWithMemo -- BOTTOMUP NOT YET WORKING + } else { + args(0).toLowerCase match { + case "topdown" => topDown + case "bottomup" => bottomUp + case "topdownmemo" => topDownWithMemo + case "topdownwithmemo" => topDownWithMemo + case _ => + print (s"Unknown option: ${args(0)}. Must be either 'topDown', 'bottomUp' or 'topDownMemo'.") + ??? + } + } + + val targetDirectory:Path = Paths.get("target", choice.name) + + for { + _ <- IO { + println("Initializing Generator...") + println(s"Output will appear in: ${targetDirectory}") + } + main <- IO { new Glossary() } + + result <- if (choice == topDown) { + main.runDirectToDisc(targetDirectory, top_down()) + } else if (choice == topDownWithMemo) { + main.runDirectToDisc(targetDirectory, top_down_memo_files()) + } else { + main.runDirectToDisc(targetDirectory, bottom_up_files()) + } + + _ <- IO { println("Make sure you run the scripts to 'fix' the generated code.") } + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/GlossaryScala.scala b/dynamicProgramming/src/main/scala/org/combinators/models/GlossaryScala.scala new file mode 100644 index 00000000..26a8b6d2 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/GlossaryScala.scala @@ -0,0 +1,162 @@ +package org.combinators.models + +/** + * sbt "dp/runMain org.combinators.modelTests.Glossary [bottomUp | topDown | topDownMemo]" + * + * Creates output files in target/bottomUp or target\topDown or target\topDownMemo + */ + +import cats.effect.{ExitCode, IO, IOApp} +import org.apache.commons.io.FileUtils +import org.combinators.dp.enhanced.EnhancedMainInterface +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import FileWithPathPersistable.* +import org.combinators.boilerplate.grid.{CountSquaresMainScala, MinPathSumMainScala, UniquePathsMainScala} +import org.combinators.boilerplate.integer.{BellNumberMainScala, DiceThrowMainScala, FibonacciMainScala, PerfectSquaresMainScala, TribonacciMainScala} +import org.combinators.boilerplate.oneSequence.{MatrixChainMultiplicationBottomUpMainScala, MatrixChainMultiplicationTopDownMainScala, MinCostClimbingStairMainScala} +import org.combinators.boilerplate.strings.{InterleaveStringsMainScala, ThreeStringsLCSMainScala} +import org.combinators.boilerplate.twoSequences.{LongestCommonSubsequenceMainScala, UncrossedLinesMainScala} +import org.combinators.dp.original.{BottomUp, GenerationOption, TopDown} + +import java.nio.file.{Path, Paths} +import scala.collection.Seq + +class GlossaryScala { + + val persistable = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path, files: Seq[FileWithPath]): IO[Unit] = { + IO { + print("Computing Files...") + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files.foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path,files: Seq[FileWithPath]): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory, files) + } yield ExitCode.Success + } +} + +object GlossaryScalaToDiskMain extends IOApp { + + // choose one of these to pass in + val topDown = TopDown() + val topDownWithMemo = TopDown(memo = true) + val bottomUp = BottomUp() + + // declare the working versions for each problem in the enhanced list + val known_enhanced_solutions:Seq[(EnhancedMainInterface, Seq[GenerationOption])] = Seq( + (new BellNumberMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new CountSquaresMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new DiceThrowMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new FibonacciMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new InterleaveStringsMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new LongestCommonSubsequenceMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new MinCostClimbingStairMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new PerfectSquaresMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new ThreeStringsLCSMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new UncrossedLinesMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), +// (new NeedlemanWunschSequenceAlignmentMainJava(), NeedlemanWunschSequenceAlignmentToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), +// (new DistinctSubsequencesMainJava(), DistinctSubsequencesToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), +// (new WildcardPatternMatchingMainJava(), WildcardPatternMatchingToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), +// (new ShortestCommonSupersequenceMainJava(), ShortestCommonSupersequenceToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), + (new TribonacciMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new UniquePathsMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + (new MinPathSumMainScala(), Seq(topDown, topDownWithMemo, bottomUp)), + + // generates but has flawed logic because of the transformation of (r,c) into (i,j) + // CHALLENGING (new MatrixChainMultiplicationMainJava(), MatrixChainMultiplicationMainDirectToDiskMain.model, Seq(topDown, topDownWithMemo, bottomUp)), + ) + + // below are the individual DP problems generated and added to `all_files`. + def top_down_memo_files(): Seq[FileWithPath] = { + + // UncrossedLinesMainJava and LCSMainJava still don't work + + val mcm_td = (new MatrixChainMultiplicationTopDownMainScala(), Seq(topDown, topDownWithMemo)) + val just_td = Seq(mcm_td) + + val others = (just_td ++ known_enhanced_solutions).filter(pair + => pair._2.contains(TopDown(memo = true))). + flatMap(pair => pair._1.filesToGenerate(TopDown(memo = true))) + + others + } + + // below are the individual DP problems generated and added to `all_files`. + def top_down(): Seq[FileWithPath] = { +// val ul = new UncrossedLinesMainJava().filesToGenerate(new UncrossedLinesModel().instantiate(), TopDown()) + //val lcs = new LCSMainJava().filesToGenerate(new LongestCommonSubsequenceModel().instantiate(), TopDown()) [HEINEMAN: not working] + // val kp = new KnapsackMainJava().filesToGenerate(new KnapsackModel().instantiate(), TopDown()) [HEINEMAN: not working] + //val nwsa = new NWSAMainJava().filesToGenerate(new NeedlemanWunschSequenceAlignmentModel().instantiate(), TopDown()) [HEINEMAN: not working] + + val mcm_td = (new MatrixChainMultiplicationTopDownMainScala(), Seq(topDown, topDownWithMemo)) + val just_td = Seq(mcm_td) + + val others = (just_td ++ known_enhanced_solutions).filter(pair + => pair._2.contains(TopDown())). + flatMap(pair => pair._1.filesToGenerate(TopDown())) + + others + } + + def bottom_up_files() : Seq[FileWithPath] = { +// val ul = new UnenhancedUncrossedLinesMainJava().filesToGenerate(new UncrossedLinesModel().instantiate(), BottomUp()) +// val lcs = new LCSMainJava().filesToGenerate(new LongestCommonSubsequenceModel().instantiate(), BottomUp()) + + val mcm_bot = (new MatrixChainMultiplicationBottomUpMainScala(), Seq(bottomUp)) + val just_bot = Seq(mcm_bot) + + val others = (just_bot ++ known_enhanced_solutions).filter(pair + => pair._2.contains(BottomUp())). + flatMap(pair => pair._1.filesToGenerate(BottomUp())) + + others + } + + def run(args: List[String]): IO[ExitCode] = { + val choice = if (args.isEmpty) { + bottomUp // <------ CHANGE this manually when you run, to generate topDown or topDownWithMemo -- BOTTOMUP NOT YET WORKING + } else { + args(0).toLowerCase match { + case "topdown" => topDown + case "bottomup" => bottomUp + case "topdownmemo" => topDownWithMemo + case "topdownwithmemo" => topDownWithMemo + case _ => + print (s"Unknown option: ${args(0)}. Must be either 'topDown', 'bottomUp' or 'topDownMemo'.") + ??? + } + } + + val targetDirectory:Path = Paths.get("target", choice.name) + + for { + _ <- IO { + println("Initializing Generator...") + println(s"Output will appear in: ${targetDirectory}") + } + main <- IO { new Glossary() } + + result <- if (choice == topDown) { + main.runDirectToDisc(targetDirectory, top_down()) + } else if (choice == topDownWithMemo) { + main.runDirectToDisc(targetDirectory, top_down_memo_files()) + } else { + main.runDirectToDisc(targetDirectory, bottom_up_files()) + } + + _ <- IO { println("Make sure you run the scripts to 'fix' the generated code.") } + } yield result + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/Model.scala b/dynamicProgramming/src/main/scala/org/combinators/models/Model.scala new file mode 100644 index 00000000..5a91ef57 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/Model.scala @@ -0,0 +1,165 @@ +package org.combinators.models + +trait ArgumentType { } + +// problem instance types go here +case class BooleanType() extends ArgumentType +case class CharType() extends ArgumentType +case class IntegerType() extends ArgumentType +case class DoubleType() extends ArgumentType +case class StringType() extends ArgumentType +case class UnitType() extends ArgumentType + +// helper for when the PD problem has multiple argument types (like an Array and an integer). +// can contain a variable number of literalExpressions, each of which is independently +case class TupleType() extends ArgumentType +case class LiteralTuple(values:LiteralExpression*) extends LiteralExpression { + def length : Int = values.length + + def tpe:ArgumentType = TupleType() +} +// possibly choose to make this Generic but that seems like overkill +trait ArrayType(val elementType:ArgumentType) extends ArgumentType + +case class IntegerArrayType() extends ArrayType(IntegerType()) +case class IntegerArray2DType() extends ArrayType(IntegerArrayType()) + +// an array of string values +case class StringArrayType() extends ArrayType(StringType()) + +class Argument (val argName:String, val argType:ArgumentType) + +/** + * For MatrixChain Multiplication, whether top-down or bottom up, the key formulation is: + * + * Input: + * A:IntegerArrayType + * + * SolutionType: + * LiteralString + * + * Solution: + * P(1, A.length-1) From this start, should be able to infer the double loop from MinSubProblemDefinition + * + * Decomposed Solutions: + * + * P(i,j) = 0, if i == j + * P(i,j) = Min (k, P(i,k) + P(k+1,j) + cost of multiplying resulting two matrices) + * for (int k = i; k < j; k++) + + + + if (i == j) { return 0; } + + int min = Integer.MAX_VALUE; // could store in array and find min but then req extra storage + for (int k = i; k < j; k++) { + // compute cost of each possible starting point for a '(' between 'i' and 'j-1' with a ')' at j + int count = helper(i, k) + helper(k+1, j) + A[i-1] * A[k] * A[j]; + if (count < min) { min = count; decision.put(key(i,j), k); } + } + + // Return minimum count + return min; + + + */ +class Range(val variable:String, start:Expression, guard:Expression, advance:Expression) +class MinSubProblemDefinition(val params:Seq[Range], definition:Expression) extends Expression { + def tpe:ArgumentType = definition.tpe +} + +abstract class Definition + +abstract class DefinitionStatement +case class ExpressionStatement(expr:Expression) extends DefinitionStatement + +// TODO: I think we need this for when multiple are needed (i.e., NumberPathsWithKCoins +case class DefinitionSequence(stmts:DefinitionStatement*) extends DefinitionStatement + +case class IfThenElseDefinition(condition: Expression, result: DefinitionStatement, elseExpression: Definition) extends Definition +case class IfThenNoElseDefinition(condition: Expression, result: Expression, elseIfs: Seq[(Expression, Expression)]) extends Definition + +// Set P(...) = compute sum of a range of other P(...) based on one-dimensional range starting at inclusiveStart +case class SumDefinition( + variable: String, + inclusiveStart: Expression, + guardContinue:Expression, + subproblemExpression: Expression, + advance: Expression +) extends Definition + +case class AccumulatorInformation(variable:String, inclusiveStart:Expression, guardCondition:Expression, advance:Expression) + +//ReturnAccumulatedDefinition("idx", "sum", zero, SelfExpression("idx") <= n, SubproblemExpression(Seq(n, SelfExpression("idx"))), SelfExpression("idx") + one) +// Accumulate values of P(...) and return as Integer +case class ReturnAccumulatedDefinition( + accumulationVariable: String, + iteration: Seq[AccumulatorInformation], + subproblemExpression: Expression, +) extends Definition + +case class MinRangeDefinition( + variable: String, + inclusiveStart: Expression, + guardContinue:Expression, + subproblemExpression: Expression, + advance: Expression +) extends Definition + +case class MaxRangeDefinition( + variable: String, + inclusiveStart: Expression, + guardContinue:Expression, + subproblemExpression: Expression, + advance: Expression + ) extends Definition + +// just lift Expression +case class ExpressionDefinition(expr:Expression) extends Definition + +// for Top-down, just return; for Bottom-Up, return assigned var +case class ReturnExpressionDefinition(expr:Expression) extends Definition + +trait ProblemOrder +case class Canonical() extends ProblemOrder +case class UpperTriangle(params:Seq[String]) extends ProblemOrder + +// trying a new approach that captures definitions. Each definition is in ordered sequence and specifies +// the essence of the problem +class EnhancedModel(val problem:String, + val input:Seq[ArgExpression], + val subproblemType:ArgumentType, // Type of solution + val solutionType:ArgumentType, // Type of return value + val solution:SubproblemInvocation, + val definition:Definition, + val answer:Definition, // all existing Expression should just use ExpressionDefinition(expr) + val mode:ProblemOrder = Canonical()) { + + def find(variable:String) : HelperExpression = { + // first locate in solution.params + if (solution.helpers.contains(variable)) { + solution.helpers(variable) + } else { + ??? + } + } + + // allows mapping to affect how DP problems are stored, typically in bottom up + def find_map(variable:String) : Expression = { + if (solution.mappers.contains(variable)) { + solution.mappers(variable) // overrides the default + } else { + find(variable) + } + } +} + +// Most DP problems solve subproblems in a canonical order, which is typified by a two-d array: solve rows first from top to bottom, +// and then within each row, columns from left to right +// +// Naturally, not all follow this. one common alternative is solving problems along the upper triangle matrix. That is, first solve as +// the base case the long diagonal. Then solve all problems on the DP[i][j+1] for those entries just above the diagonal; then dp[i][j+2] +// for all values two above the diagonal and so on. + +// Model has bounds and cases +// EnhancedModel has solution and definitions diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/CountSquares.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/CountSquares.scala new file mode 100644 index 00000000..0990ace4 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/CountSquares.scala @@ -0,0 +1,78 @@ +package org.combinators.models.enhancedModels.grid + +import org.combinators.models._ + +/** + * Name: Count Squares + * Description: + * Given an m x n binary matrix, return how many square submatrices have all ones. + * + * Recurrence: + * P(r, c) = 0 if grid[r][c] == 0 + * P(r, c) = 1 if grid[r][c] == 1 and (r==0 || c==0) + * P(r, c) = min(P(r-1,c-1), P(r-1,c), P(r,c-1)) + 1 otherwise + */ +class CountSquares { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val grid = ArgExpression(0, "grid", IntegerArray2DType(), "g") + + val numRows = ArrayLengthExpression(grid) + val numCols = ArrayLengthExpression(ArrayElementExpression(grid, zero)) + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") < numRows, numRows) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") < numCols, numCols) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + // grid[r][c] + val gridVal = ArrayElementExpression(ArrayElementExpression(grid, r), c) + + // min(P(r-1,c-1), min(P(r-1,c), P(r,c-1))) + 1 + val minThree = MinExpression( + SubproblemExpression(Seq(r - one, c - one)), + MinExpression( + SubproblemExpression(Seq(r - one, c)), + SubproblemExpression(Seq(r, c - one)) + ) + ) + one + + // grid[r][c] == 1: edge cells get 1, interior cells get minThree + val onesCase = IfThenElseDefinition( + r == zero || c == zero, + ExpressionStatement(one), + ExpressionDefinition(minThree) + ) + + // grid[r][c] == 0: no squares possible here + val definition = IfThenElseDefinition( + gridVal == zero, + ExpressionStatement(zero), + onesCase + ) + + val final_answer = ReturnAccumulatedDefinition( + "sum", + Seq( + AccumulatorInformation("ridx", zero, SelfExpression("ridx") < numRows, SelfExpression("ridx") + one), + AccumulatorInformation("cidx", zero, SelfExpression("cidx") < numCols, SelfExpression("cidx") + one), + ), + SubproblemExpression(Seq(SelfExpression("ridx"), SelfExpression("cidx"))) + ) + + val CS: EnhancedModel = new EnhancedModel( + "CountSquares", + List(grid), + subproblemType = IntegerType(), + solutionType = IntegerType(), + soln, + definition, + answer = final_answer // figure out how to sum elements using expressions + ) + + CS + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/GridWithObstacles.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/GridWithObstacles.scala new file mode 100644 index 00000000..210b28eb --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/GridWithObstacles.scala @@ -0,0 +1,69 @@ +package org.combinators.models.enhancedModels.grid + +import org.combinators.models.* + +/** + * Name: Grid With Obstacles + * Description: + * Given an m x n grid, find the number of unique paths from the top-left + * to the bottom-right corner. You can only move down or right at each step, and you + * must avoid cells containing a 1 (obstacle). This is a variation of UniquePaths + * + * Recurrence: + * P(r, 0) = 1 only one way to reach any cell in the first column (go straight down) + * P(0, c) = 1 only one way to reach any cell in the first row (go straight right) + * P(r, c) = P(r-1, c) + P(r, c-1) + */ +class GridWithObstacles { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val grid = ArgExpression(0, "grid", IntegerArray2DType(), "g") + + val m = ArrayLengthExpression(grid) + val n = ArrayLengthExpression(ArrayElementExpression(grid, zero)) + val bound = List(grid) + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") < m, m) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") < n, n) + + val helpers = Map("r" -> r, "c" -> c) + val sol = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + // if grid[r][c] = 0 then P(r, c) = P(r-1, c) + P(r, c-1), otherwise must equal 0 + val subproblemTraversal = IfThenElseDefinition(ArrayElementExpression(ArrayElementExpression(grid, r), c) == one, + ExpressionStatement(zero), + ExpressionDefinition( + SubproblemExpression(Seq(r - one, c)) + SubproblemExpression(Seq(r, c - one)) + )) + + // P(0, c) = 1: only one way along the top row + val baseCase2 = IfThenElseDefinition( + r == zero, + ExpressionStatement(one), + subproblemTraversal + ) + + // P(r, 0) = 1: only one way along the left column + val definition = IfThenElseDefinition( + c == zero, + ExpressionStatement(one), + baseCase2 + ) + + val GWO: EnhancedModel = new EnhancedModel( + "GridWithObstacles", + bound, + subproblemType = IntegerType(), + solutionType = IntegerType(), + sol, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(m - one, n - one)) + ) + ) + + GWO + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/MinPathSum.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/MinPathSum.scala new file mode 100644 index 00000000..67135586 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/MinPathSum.scala @@ -0,0 +1,81 @@ +package org.combinators.models.enhancedModels.grid + +import org.combinators.models._ + +/** + * Name: Minimum Path Sum + * Description: + * Given an m x n grid filled with non-negative numbers, find a path from + * top-left to bottom-right which minimizes the sum of all numbers along its path. + * You can only move down or right at each step. + * + * Recurrence: + * P(0, 0) = grid[0][0] + * P(r, 0) = P(r-1, 0) + grid[r][0] down left column + * P(0, c) = P(0, c-1) + grid[0][c] across top row + * P(r, c) = min(P(r-1,c), P(r,c-1)) + grid[r][c] + */ +class MinPathSum { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val grid = ArgExpression(0, "grid", IntegerArray2DType(), "g") + val bound = List(grid) + + val numRows = ArrayLengthExpression(grid) + val numCols = ArrayLengthExpression(ArrayElementExpression(grid, zero)) + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") < numRows, numRows) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") < numCols, numCols) + + val helpers = Map("r" -> r, "c" -> c) + val sol = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + // grid[r][c] + val gridVal = ArrayElementExpression(ArrayElementExpression(grid, r), c) + + // P(r, c) = min(P(r-1, c), P(r, c-1)) + grid[r][c] + val general = ExpressionDefinition( + MinExpression( + SubproblemExpression(Seq(r - one, c)), + SubproblemExpression(Seq(r, c - one)) + ) + gridVal + ) + + // P(0, c) = P(0, c-1) + grid[0][c] + val topRow = IfThenElseDefinition( + r == zero, + ExpressionStatement(SubproblemExpression(Seq(zero, c - one)) + gridVal), + general + ) + + // P(r, 0) = P(r-1, 0) + grid[r][0] + val leftCol = IfThenElseDefinition( + c == zero, + ExpressionStatement(SubproblemExpression(Seq(r - one, zero)) + gridVal), + topRow + ) + + // P(0, 0) = grid[0][0] + val definition = IfThenElseDefinition( + r == zero && c == zero, + ExpressionStatement(gridVal), + leftCol + ) + + val MPS: EnhancedModel = new EnhancedModel( + "MinPathSum", + bound, + subproblemType = IntegerType(), + solutionType = IntegerType(), + sol, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(numRows - one, numCols - one)) + ) + ) + + MPS + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/NumberPathsWithKCoins.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/NumberPathsWithKCoins.scala new file mode 100644 index 00000000..59b799c0 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/NumberPathsWithKCoins.scala @@ -0,0 +1,69 @@ +package org.combinators.models.enhancedModels.grid + +import org.combinators.models.* + +/** + * Name: Number Paths With Exactly K Coins + * Description: + * Given a matrix mat[][] where each cell contains a certain number of coins, and an integer k, + * count the total number of distinct paths from the top-left cell to the bottom-right cell such + * that the sum of coins collected along the path is exactly k. + * + * URL: https://www.geeksforgeeks.org/dsa/number-of-paths-with-exactly-k-coins/ + * + * Recurrence: + * P(r, 0) = 1 only one way to reach any cell in the first column (go straight down) + * P(0, c) = 1 only one way to reach any cell in the first row (go straight right) + * P(r, c) = P(r-1, c) + P(r, c-1) + */ +@deprecated(message = "NOT WORKING! NEEDS multiple statements in BODY and model cannot support this yet") +class NumberPathsWithKCoins { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val grid = ArgExpression(0, "grid", IntegerArray2DType(), "g") + val kParam = ArgExpression(1, "k", IntegerType(), "k") + + val m = ArrayLengthExpression(grid) + val n = ArrayLengthExpression(ArrayElementExpression(grid, zero)) + val bound = List(grid, kParam) + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") < m, m) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") < n, n) + val k: HelperExpression = HelperExpression("k", zero, SelfExpression("k") < kParam, kParam + one) + + val helpers = Map("r" -> r, "c" -> c, "k" -> k) + val sol = SubproblemInvocation(order = Seq("r", "c", "k"), helpers = helpers, returnType = IntegerType()) + + val gridRC = ArrayElementExpression(ArrayElementExpression(grid, r), c) + val enoughCoins = k - gridRC >= zero + + // if not exceeded total, then P(r, c) = P(r-1, c) + P(r, c-1), otherwise must equal 0 + val subproblemTraversal = IfThenElseDefinition(AndExpression(enoughCoins, r > zero), + ExpressionStatement(ArrayElementExpression(ArrayElementExpression(grid, r), c) + SubproblemExpression(Seq(r - one, c, k - gridRC))), + ExpressionDefinition(zero) + ) + + // P(r, 0) = 1: only one way along the left column + val definition = IfThenElseDefinition( + ArrayElementExpression(ArrayElementExpression(grid, r), c) <= k, + ExpressionStatement(one), + subproblemTraversal + ) + + val GWO: EnhancedModel = new EnhancedModel( + "NumberPathsWithKCoins", + bound, + subproblemType = IntegerType(), + solutionType = IntegerType(), + sol, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(m - one, n - one, k)) + ) + ) + + GWO + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/UniquePaths.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/UniquePaths.scala new file mode 100644 index 00000000..78c32d3f --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/grid/UniquePaths.scala @@ -0,0 +1,64 @@ +package org.combinators.models.enhancedModels.grid + +import org.combinators.models._ + +/** + * Name: Unique Paths + * Description: + * Given an m x n grid, find the number of unique paths from the top-left + * to the bottom-right corner. You can only move down or right at each step. + * + * Recurrence: + * P(r, 0) = 1 only one way to reach any cell in the first column (go straight down) + * P(0, c) = 1 only one way to reach any cell in the first row (go straight right) + * P(r, c) = P(r-1, c) + P(r, c-1) + */ +class UniquePaths { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val m = ArgExpression(0, "m", IntegerType(), "r") + val n = ArgExpression(1, "n", IntegerType(), "c") + val bound = List(m, n) + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") < m, m) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") < n, n) + + val helpers = Map("r" -> r, "c" -> c) + val sol = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + // P(r, c) = P(r-1, c) + P(r, c-1) + val subproblemTraversal = ExpressionDefinition( + SubproblemExpression(Seq(r - one, c)) + SubproblemExpression(Seq(r, c - one)) + ) + + // P(0, c) = 1: only one way along the top row + val baseCase2 = IfThenElseDefinition( + r == zero, + ExpressionStatement(one), + subproblemTraversal + ) + + // P(r, 0) = 1: only one way along the left column + val definition = IfThenElseDefinition( + c == zero, + ExpressionStatement(one), + baseCase2 + ) + + val UP: EnhancedModel = new EnhancedModel( + "UniquePaths", + bound, + subproblemType = IntegerType(), + solutionType = IntegerType(), + sol, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(m - one, n - one)) + ) + ) + + UP + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/BellNumber.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/BellNumber.scala new file mode 100644 index 00000000..5c9ec4dd --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/BellNumber.scala @@ -0,0 +1,55 @@ +package org.combinators.models.enhancedModels.integer + +import org.combinators.models._ + +/** + * Name: Bell Number + * Description: + * Given a set of n elements, find the number of ways of partitioning it + * + * Example: + * n=2 + * number of ways = 2, since set {1,2} can be partition as {{1}, {2}} and {1,2} + */ +class BellNumber { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val n = ArgExpression(0, "n", IntegerType(), "i") + val bound = List(n) + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= n, n + one) // in_range is not essential since this is not an argument to helper/subproblem + val k: HelperExpression = HelperExpression("k", zero, SelfExpression("k") <= n, n + one) // in_range is not essential since this is not an argument to helper/subproblem + + val helperTable = Map( "i" -> i, "k" -> k ) + val sol = SubproblemInvocation(Seq("i", "k"), helpers = helperTable) + + val expr = k * SubproblemExpression(Seq(i - one, k)) + SubproblemExpression(Seq(i - one, k - one)) + + // Parition of i elements by k is ONE, whenever i==k (like C (n,n)) or i==1 (like C(n,1)). + val base3 = IfThenElseDefinition(i == k || k == one, ExpressionStatement(one), ExpressionDefinition(expr)) + val base2 = IfThenElseDefinition(i == zero || k == zero, ExpressionStatement(zero), base3) + val dt_definition = IfThenElseDefinition(i == zero && k == zero, ExpressionStatement(one), base2) + + // Top-Down would be OK with SumDefinition, but we cannot use this for BottomUp, which sets individual + // DP[] entries based on the Sum. Instead, we need a new + val final_answer = ReturnAccumulatedDefinition( + "sum", + Seq(AccumulatorInformation("idx", zero, SelfExpression("idx") <= n, SelfExpression("idx") + one)), + SubproblemExpression(Seq(n, SelfExpression("idx"))) + ) + + val BellNumber = new EnhancedModel("BellNumber", + bound, + subproblemType = IntegerType(), // helper methods and intermediate problems are int + solutionType = StringType(), // how a solution is represented (not yet effective) + sol, + dt_definition, + answer = final_answer + ) + + BellNumber + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/DiceThrow.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/DiceThrow.scala new file mode 100644 index 00000000..256b4ebe --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/DiceThrow.scala @@ -0,0 +1,52 @@ +package org.combinators.models.enhancedModels.integer + +import org.combinators.models._ + +class DiceThrow { + /** + * Name: Dice Throw + * Description: + * Given n dices each with m faces, numbered from 1 to m, find the number of ways to get sum x, + * which is the summation of values on each face + * + * Example: + * m=2, n=3, x=6 + * there is only 1 way to get the sum 6 using 3 dices from 1 to 2 + */ + + def model: EnhancedModel = { + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val m = ArgExpression(2, "m", IntegerType(), "m") // m never changes and is not part of helper + val n = ArgExpression(0, "n", IntegerType(), "i") // not sure if 'i' is used + val x = ArgExpression(1, "x", IntegerType(), "j") + + val bound_ps = List(m, n, x) + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= n, n + one) // need to be zero for BottomUp to be able to trigger base case within loop. + val j: HelperExpression = HelperExpression("j", zero, SelfExpression("j") <= x, x + one) + + val k: HelperExpression = HelperExpression("k", i, SelfExpression("k") <= m, m) // in_range is not essential since this is not an argument to helper/subproblem + + val additiveExpression:Expression = SubproblemExpression(Seq(i - one, j - k)) + val k_sum = SumDefinition("k", one, k <= m && zero <= j - k, additiveExpression, k + one) + + val helperTable = Map("i" -> i, "j" -> j, "k" -> k) + val sol_dt = SubproblemInvocation(Seq("i", "j"), helpers = helperTable) + + val base2 = IfThenElseDefinition(i == zero || j <= zero, ExpressionStatement(zero), k_sum) + val dt_definition = IfThenElseDefinition(i == zero && j == zero, ExpressionStatement(one), base2) + + val DiceThrow = new EnhancedModel("DiceThrow", + bound_ps, + subproblemType = IntegerType(), // helper method is an int + solutionType = StringType(), // solution is a string + sol_dt, + dt_definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(n, x))) + ) + + DiceThrow + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/Fibonacci.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/Fibonacci.scala new file mode 100644 index 00000000..472c3696 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/Fibonacci.scala @@ -0,0 +1,37 @@ +package org.combinators.models.enhancedModels.integer + +import org.combinators.models._ + +class Fibonacci { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + // MatrixChainMultiplication has an array of N+1 integers,representing N 2D Matrices + val n = ArgExpression(0, "n", IntegerType(), "i") + val bound = List(n) + + // COULD be inferred from the ArgExpression list, but this lets us name variable to use in iterator + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= n, n + one) // only one argument, i + + // what the compute() method calls with helper(1, nums.length-1) + val sol = SubproblemInvocation(Seq("i"), helpers = Map("i" -> i)) + + val oneCase = IfThenElseDefinition(i == one, ExpressionStatement(one), + ExpressionDefinition(SubproblemExpression(Seq(i - one)) + SubproblemExpression(Seq(i - two)))) + + val zeroCase = IfThenElseDefinition(i == zero, ExpressionStatement(zero), oneCase) + + val Fib = new EnhancedModel("Fibonacci", + bound, + subproblemType = IntegerType(), // helper methods and intermediate problems are int + solutionType = StringType(), // how a solution is represented (not yet effective) + sol, + zeroCase, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(n)))) + + Fib + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/PerfectSquares.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/PerfectSquares.scala new file mode 100644 index 00000000..558f7a27 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/PerfectSquares.scala @@ -0,0 +1,37 @@ +package org.combinators.models.enhancedModels.integer + +import org.combinators.models._ + +class PerfectSquares { + def model: EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + /* Perfect Square. */ + val n = ArgExpression(0, "n", IntegerType(), "i") // not sure if 'i' is used + val bound_ps = List(n) + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= n, n + one) + val k: HelperExpression = HelperExpression("k", zero, SelfExpression("k") * SelfExpression("k") <= n, n) + + val helperTable_ps = Map("i" -> i, "k" -> k) // Boy this is awkward: need k as helper but not in invocation + val sol_ps = SubproblemInvocation(Seq("i"), helpers = helperTable_ps) + + val ps_subprobExpr = SubproblemExpression(Seq(i - k * k)) + one + val def_ps = MinRangeDefinition("k", one, k * k <= i, ps_subprobExpr, k + one) + val ps_inner_definition = IfThenElseDefinition(i == one, ExpressionStatement(one), def_ps) + val ps_definition = IfThenElseDefinition(i == zero, ExpressionStatement(zero), ps_inner_definition) + + val PerfectSquare = new EnhancedModel("PerfectSquare", + bound_ps, + subproblemType = IntegerType(), // helper method is an int + solutionType = StringType(), // solution is a string + sol_ps, + ps_definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(n))) + ) + + PerfectSquare + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/Tribonacci.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/Tribonacci.scala new file mode 100644 index 00000000..87977696 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/integer/Tribonacci.scala @@ -0,0 +1,52 @@ +package org.combinators.models.enhancedModels.integer + +import org.combinators.models._ + +class Tribonacci { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + val two = LiteralInt(2) + val three = LiteralInt(3) + + val n = ArgExpression(0, "n", IntegerType(), "i") + val bound = List(n) + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= n, n + one) + + val sol = SubproblemInvocation(Seq("i"), helpers = Map("i" -> i)) + + val twoCase = IfThenElseDefinition( + i == two, + ExpressionStatement(one), + ExpressionDefinition( + SubproblemExpression(Seq(i - one)) + + SubproblemExpression(Seq(i - two)) + + SubproblemExpression(Seq(i - three)) + ) + ) + + val oneCase = IfThenElseDefinition( + i == one, + ExpressionStatement(one), + twoCase + ) + + val definition = IfThenElseDefinition( + i == zero, + ExpressionStatement(zero), + oneCase + ) + + val Trib = new EnhancedModel("Tribonacci", + bound, + subproblemType = IntegerType(), + solutionType = IntegerType(), + sol, + definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(n))) + ) + + Trib + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/JumpGame.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/JumpGame.scala new file mode 100644 index 00000000..556d7471 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/JumpGame.scala @@ -0,0 +1,47 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + +class JumpGame { + + def model: EnhancedModel = { + + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val arr = ArgExpression(0, "arr", IntegerArrayType(), "j") // j is the iterator + //val index = ArgExpression(1, "i", IntegerType(), "i") + val arr_length = ArrayLengthExpression(arr) + //val eleAtIndex = ArrayElementExpression(arr, index) + //val loopBound = AdditionExpression(eleAtIndex, index) + val bound = List(arr) + + val i:HelperExpression = HelperExpression("i", one, SelfExpression("i") <= arr_length, arr_length + one) + + val result_min = + MinRangeDefinition( + "j", + i + one, + SelfExpression("j") <= arr_length, + SubproblemExpression(Seq(SelfExpression("j"))), + SelfExpression("j") + one + ) + + val helperTable = Map("i" -> i) + + val sol_dt = SubproblemInvocation(Seq("i"), helpers = helperTable) + + val basecase = IfThenElseDefinition(arr_length - one <= arr_length, ExpressionStatement(zero), result_min) + + val JumpGame = new EnhancedModel("JumpGame", + bound, + subproblemType = IntegerType(), + solutionType = IntegerType(), + solution = sol_dt, + definition = basecase, + answer = ReturnExpressionDefinition(SubproblemExpression((Seq(zero)))) + ) + + JumpGame + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/LongestIncreasingSubsequence.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/LongestIncreasingSubsequence.scala new file mode 100644 index 00000000..994e35f2 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/LongestIncreasingSubsequence.scala @@ -0,0 +1,42 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + +class LongestIncreasingSubsequence { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + val arr = ArgExpression(0, "arr", IntegerArrayType(), "i") + val bound = List(arr) + + val lenArr = ArrayLengthExpression(arr) + + // COULD be inferred from the ArgExpression list, but this lets us name variable to use in iterator + val i: HelperExpression = HelperExpression("i", one, SelfExpression("i") <= lenArr, lenArr) // only one argument, i + + // what the compute() method calls with helper(1, nums.length-1) + val j: HelperExpression = HelperExpression("j", zero, SelfExpression("j") < i, lenArr) // k will always be within this range + + val sol = SubproblemInvocation(Seq("i"), helpers = Map("i" -> i, "j" -> j)) + + val subprobExpr = SubproblemExpression(Seq(j)) + val checkExpr = TernaryExpression(ArrayElementExpression(arr, i) < ArrayElementExpression(arr, j), subprobExpr + one, zero) + + val innerLoop = MaxRangeDefinition("j",zero, j < i, checkExpr, j+one) + + val zeroCase = IfThenElseDefinition(i == zero, ExpressionStatement(one), innerLoop) + + val Fib = new EnhancedModel("LIS", + bound, + subproblemType = IntegerType(), // helper methods and intermediate problems are int + solutionType = StringType(), // how a solution is represented (not yet effective) + sol, + zeroCase, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(ArrayLengthExpression(arr))))) + + Fib + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/LongestValidParentheses.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/LongestValidParentheses.scala new file mode 100644 index 00000000..c29fd418 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/LongestValidParentheses.scala @@ -0,0 +1,46 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + + +class LongestValidParentheses { + def model:EnhancedModel = { + + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + val str = ArgExpression(0, "str", StringType(), "i") + val bound = List(str) + + val strlen = StringLengthExpression(str) + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= strlen - one, strlen) + val j: HelperExpression = HelperExpression("j", zero, SelfExpression("j") <= one, two) + + val last = SubproblemExpression(Seq(i-one,zero)) + + val cond = CharAtExpression(str, i) == LiteralChar(')') && + (zero <= i - last - one) && + CharAtExpression(str, i - last - one) == LiteralChar('(') + + val sol = SubproblemInvocation(Seq("i", "j"), helpers = Map("i" -> i,"j" -> j)) + + val ternary = TernaryExpression(zero <= (i - last - two), SubproblemExpression(Seq(i - last - two, zero)), zero) + val complexValue = (last + two) + ternary + + val complexCase = IfThenElseDefinition(cond, ExpressionStatement(complexValue), ExpressionDefinition(zero)) + val maxFinder = MaxExpression(SubproblemExpression(Seq(i, zero)), SubproblemExpression(Seq(i - one, one))) + val maxCase = IfThenElseDefinition(j == one, ExpressionStatement(maxFinder), complexCase) + val zeroCase = IfThenElseDefinition(i == zero, ExpressionStatement(zero), maxCase) + + val Fib = new EnhancedModel("LVP", + bound, + subproblemType = IntegerType(), // helper methods and intermediate problems are int + solutionType = StringType(), // how a solution is represented (not yet effective) + sol, + zeroCase, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(str) - one, one)))) + + Fib + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MatrixChainMultiplicationBU.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MatrixChainMultiplicationBU.scala new file mode 100644 index 00000000..f0e5b0b8 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MatrixChainMultiplicationBU.scala @@ -0,0 +1,56 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + +class MatrixChainMultiplicationBU { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + // MatrixChainMultiplication has an array of N+1 integers,representing N 2D Matrices + val array = ArgExpression(0, "nums", IntegerArrayType(), "c") + val bound = List(array) + + // Need to find way to get these (i,j) into the EnhancedModel. Apply the mapping that iteration takes place over (r,c) and there is + // mapping of i = r+c+2 and j = c+1. The inherent problem search is upper triangle matrix of the P(i,j) space, which turns out to + // be upper left triangular matrix over (r,c) + val c: HelperExpression = HelperExpression("c", two, SelfExpression("c") <= ArrayLengthExpression(array) - one, ArrayLengthExpression(array) + one) + val r: HelperExpression = HelperExpression("r", one, SelfExpression("r") <= ArrayLengthExpression(array) - c, ArrayLengthExpression(array) + one) + + val k: HelperExpression = HelperExpression("k", r, SelfExpression("k") < (r + c - one), ArrayLengthExpression(array)) // k will always be within this range + + val helpers = Map("c" -> c, "r" -> r) + val mappers = Map("c" -> r, "r" -> (r + c - one)) // controls how problems are "mapped" into the dp[i][j] design space + val sol = SubproblemInvocation(Seq("c", "r"), helpers = helpers, mappers = mappers) + + /* + * This is a form of decomposition that applies to upper triangle of the P problem space. + * + * P(i,j) = 0, if i == j + * P(i,j) = Min (k, P(i,k) + P(k+1,j) + cost of multiplying resulting two matrices) + * for (int k = i; k < j; k++) + */ + val subprobExpr = SubproblemExpression(Seq(r, k)) + SubproblemExpression(Seq(k + one, r + c - one)) + array(r - one) * array(k) * array(r + c - one) + + // Min range definition for k in range from i (inclusive) to j (exclusive) with an advance of k+1 + val defij = MinRangeDefinition("k", r, k < r + c - one, subprobExpr, k + one) + + val mcm_definition = IfThenElseDefinition(r == r + c - one, ExpressionStatement(zero), defij) + + val MCM = new EnhancedModel("MatrixChainMultiplication", + bound, + subproblemType = IntegerType(), // helper methods and intermediate problems are int + solutionType = StringType(), // how a solution is represented + sol, + mcm_definition, + mode = UpperTriangle(Seq("c", "r")), + + // answer can be found in dp[1][n] + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(one, ArrayLengthExpression(array) - one))) + ) + + MCM + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MatrixChainMultiplicationTD.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MatrixChainMultiplicationTD.scala new file mode 100644 index 00000000..883f5a4e --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MatrixChainMultiplicationTD.scala @@ -0,0 +1,52 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + +class MatrixChainMultiplicationTD { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + // MatrixChainMultiplication has an array of N+1 integers,representing N 2D Matrices + val array = ArgExpression(0, "nums", IntegerArrayType(), "c") + val bound = List(array) + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= ArrayLengthExpression(array), ArrayLengthExpression(array)) // MOST of this unnecessary + val j: HelperExpression = HelperExpression("j", zero, SelfExpression("i") <= ArrayLengthExpression(array), ArrayLengthExpression(array)) // MOST of this unnecessary + + val k: HelperExpression = HelperExpression("k", i, SelfExpression("k") < j, ArrayLengthExpression(array)) // k will always be within this range + + val helpers = Map("i" -> i, "j" -> j) + val sol = SubproblemInvocation(Seq("i", "j"), helpers = helpers) // seq(c,r) is for BOTTOM UP only but i,j are included for TOP DOWN + + /* + * This is a form of decomposition that applies to upper triangle of the P problem space. + * + * P(i,j) = 0, if i == j + * P(i,j) = Min (k, P(i,k) + P(k+1,j) + cost of multiplying resulting two matrices) + * for (int k = i; k < j; k++) + */ + val subprobExpr = SubproblemExpression(Seq(i, k)) + SubproblemExpression(Seq(k + one, j)) + array(i - one) * array(k) * array(j) + + // Min range definition for k in range from i (inclusive) to j (exclusive) with an advance of k+1 + val defij = MinRangeDefinition("k", i, k < j, subprobExpr, k + one) + + val mcm_definition = IfThenElseDefinition(i == j, ExpressionStatement(zero), defij) + + val MCM = new EnhancedModel("MatrixChainMultiplication", + bound, + subproblemType = IntegerType(), // helper methods and intermediate problems are int + solutionType = StringType(), // how a solution is represented + sol, + mcm_definition, + mode = UpperTriangle(Seq("i", "j")), + + // answer can be found in dp[1][n] + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(one, ArrayLengthExpression(array) - one))) + ) + + MCM + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MaximalIndependentSetPath.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MaximalIndependentSetPath.scala new file mode 100644 index 00000000..22a4f185 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MaximalIndependentSetPath.scala @@ -0,0 +1,63 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + +class MaximalIndependentSetPath { + def model:EnhancedModel = { + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + val path = ArgExpression(0, "path", IntegerArrayType(), "i") + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= ArrayLengthExpression(path), ArrayLengthExpression(path) + one) + + val helpers = Map("i" -> i) + val soln = SubproblemInvocation(order=Seq("i"), helpers = helpers, returnType = IntegerType()) + +// val subproblemTraversal = IfThenElseDefinition( +// CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), +// ExpressionStatement(SubproblemExpression(Seq(r - one, c - one)) + one), +// ExpressionDefinition( +// MaxExpression( +// SubproblemExpression(Seq(r, c - one)), +// SubproblemExpression(Seq(r - one, c)) +// ) +// ) +// ) + val condition1 = LessThanOrEqualExpression(i, zero) + val condition2 = LessThanOrEqualExpression(i, one) + + val subproblem1 = SubproblemExpression(Seq(i - two)) + val subproblem2 = SubproblemExpression(Seq(i - one)) + + val subDefinition= IfThenElseDefinition( + condition2, + ExpressionStatement(ArrayElementExpression(path, i - one)), + ExpressionDefinition( + MaxExpression( + subproblem1 + ArrayElementExpression(path, i - one), + subproblem2 + ) + ) + ) + + val definition = IfThenElseDefinition( + condition1, + ExpressionStatement(zero), + subDefinition + ) + + val MIPS: EnhancedModel = new EnhancedModel( + "MaximalIndependentSetPath", + List(path), + subproblemType = IntegerType(), + solutionType = StringType(), + soln, + definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(ArrayLengthExpression(path)))) + ) + + MIPS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MinCostClimbingStair.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MinCostClimbingStair.scala new file mode 100644 index 00000000..1239e30d --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/oneSequence/MinCostClimbingStair.scala @@ -0,0 +1,55 @@ +package org.combinators.models.enhancedModels.oneSequence + +import org.combinators.models._ + +class MinCostClimbingStair { + def model:EnhancedModel = { + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val two: LiteralInt = LiteralInt(2) + + val costs = ArgExpression(0, "costs", IntegerArrayType(), "i") + val bounds = List(costs) + + // COULD be inferred from the ArgExpression list, but this lets us name variable to use in iterator + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") < ArrayLengthExpression(costs), ArrayLengthExpression(costs)) + + // what the compute() method calls with helper(s1.length(), s2.length()) + val helpers = Map("i" -> i) + val sol = SubproblemInvocation(order=Seq("i"), helpers = helpers, returnType = IntegerType()) + + /* + * P(i,j,k) = 0, if i == 0 || j == 0 || k == 0 for all Ranges + * P(i,j,k) = Max of three subcases + */ + + // return cost[i] + Math.min(helper_topdown(i - 1), + // helper_topdown(i - 2)); + val recursive_case = ArrayElementExpression(costs, i) + MinExpression(SubproblemExpression(Seq(i - one)), SubproblemExpression(Seq(i - two))) + + // if (i == 0 || i == 1) { + // return cost[i]; + // } + val mccs_definition = IfThenElseDefinition((i == zero) || (i == one), + ExpressionStatement(ArrayElementExpression(costs, i)), + ExpressionDefinition(recursive_case)) + + + val MCCS = new EnhancedModel("MinCostClimbingStair", + bounds, + subproblemType = IntegerType(), // helper() method returns int + solutionType = StringType(), // solution is a string, showing where characters come from S1 with parens + sol, + mccs_definition, + + // how to determine answer + answer = ReturnExpressionDefinition(TernaryExpression(ArrayLengthExpression(costs) == one, + ArrayElementExpression(costs, zero), + MinExpression( + SubproblemExpression(Seq(ArrayLengthExpression(costs) - one)), + SubproblemExpression(Seq(ArrayLengthExpression(costs) - two))))) + ) + + MCCS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/strings/InterleaveStrings.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/strings/InterleaveStrings.scala new file mode 100644 index 00000000..7a8c910b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/strings/InterleaveStrings.scala @@ -0,0 +1,77 @@ +package org.combinators.models.enhancedModels.strings + +import org.combinators.models._ + +class InterleaveStrings { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + // Interleaving strings really explores space over (s1,s2) and uses s3 as a target so it isn't part of the search space. + val s1 = ArgExpression(0, "s1", StringType(), "i1") + val s2 = ArgExpression(1, "s2", StringType(), "i2") + val s3 = ArgExpression(2, "s3", StringType(), "i3") + val bounds = List(s1, s2, s3) + + // COULD be inferred from the ArgExpression list, but this lets us name variable to use in iterator + val i1: HelperExpression = HelperExpression("i1", zero, SelfExpression("i1") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val i2: HelperExpression = HelperExpression("i2", zero, SelfExpression("i2") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + // what the compute() method calls with helper(s1.length(), s2.length()) + val helpers = Map("i1" -> i1, "i2" -> i2) + val sol = SubproblemInvocation(order=Seq("i1", "i2"), helpers = helpers, returnType = BooleanType()) + + /* + * P(i,j) = 0, if i == j + * P(i,j) = Min (k, P(i,k) + P(k+1,j) + cost of multiplying resulting two matrices) + * for (int k = i; k < j; k++) + */ + + val case_final = OrExpression( + AndExpression( + CharAtExpression(s1, i1 - one) == CharAtExpression(s3, i1 + i2 - one), + SubproblemExpression(Seq(i1 - one, i2)) + ), + AndExpression( + CharAtExpression(s2, i2 - one) == CharAtExpression(s3, i1 + i2 - one), + SubproblemExpression(Seq(i1, i2 - one)) + ) + ) + + val case_5 = IfThenElseDefinition(i2 == zero, + ExpressionStatement((CharAtExpression(s1, i1 - one) == CharAtExpression(s3, i1 - one)) && SubproblemExpression(Seq(i1 - one, zero))), + ExpressionDefinition(case_final)) + + val case_4 = IfThenElseDefinition(i1 == zero, + ExpressionStatement((CharAtExpression(s2, i2 - one) == CharAtExpression(s3, i2 - one)) && SubproblemExpression(Seq(zero, i2 - one))), + case_5) + + val case_3 = IfThenElseDefinition((i1 == zero) && (i2==zero), + ExpressionStatement(LiteralBoolean(true)), + case_4) + + val case_2 = IfThenElseDefinition(StringLengthExpression(s3) < i1 + i2, + ExpressionStatement(LiteralBoolean(false)), + case_3) + + val case_1 = IfThenElseDefinition(StringLengthExpression(s2) < i2, + ExpressionStatement(LiteralBoolean(false)), + case_2) + + val ils_definition = IfThenElseDefinition(StringLengthExpression(s1) < i1, + ExpressionStatement(LiteralBoolean(false)), + case_1) + + val ILS = new EnhancedModel("InterleavingStrings", + bounds, + subproblemType = BooleanType(), // helper() method returns boolean + solutionType = StringType(), // solution is a string, showing where characters come from S1 with parens + sol, + ils_definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2)))) + ) + + ILS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/strings/ThreeStringLCS.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/strings/ThreeStringLCS.scala new file mode 100644 index 00000000..fb113709 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/strings/ThreeStringLCS.scala @@ -0,0 +1,51 @@ +package org.combinators.models.enhancedModels.strings + +import org.combinators.models._ + +class ThreeStringLCS { + def model:EnhancedModel = { + // Needed for conditions and fib(n-1) and fib(n-2) + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "i") + val s2 = ArgExpression(1, "s2", StringType(), "j") + val s3 = ArgExpression(2, "s3", StringType(), "k") + val bounds = List(s1, s2, s3) + + // COULD be inferred from the ArgExpression list, but this lets us name variable to use in iterator + val i: HelperExpression = HelperExpression("i", one, SelfExpression("i") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val j: HelperExpression = HelperExpression("j", one, SelfExpression("j") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + val k: HelperExpression = HelperExpression("k", one, SelfExpression("k") <= StringLengthExpression(s3), StringLengthExpression(s3) + one) + + // what the compute() method calls with helper(s1.length(), s2.length()) + val helpers = Map("i" -> i, "j" -> j, "k" -> k) + val sol = SubproblemInvocation(order=Seq("i", "j", "k"), helpers = helpers, returnType = IntegerType()) + + /* + * P(i,j,k) = 0, if i == 0 || j == 0 || k == 0 for all Ranges + * P(i,j,k) = Max of three subcases + */ + val recursive_case = MaxExpression(SubproblemExpression(Seq(i - one, j, k)), + MaxExpression(SubproblemExpression(Seq(i, j - one, k)), + SubproblemExpression(Seq(i, j, k - one)))) + + val strings_case = IfThenElseDefinition(CharAtExpression(s1, i - one) == CharAtExpression(s2, j - one) && + CharAtExpression(s2, j - one) == CharAtExpression(s3, k - one), + ExpressionStatement(SubproblemExpression(Seq(i - one, j - one, k - one)) + one), + ExpressionDefinition(recursive_case)) + + val tslcs_definition = IfThenElseDefinition(i == zero || j == zero || k == zero, ExpressionStatement(zero), strings_case) + + val TSLCS = new EnhancedModel("ThreeStringLCS", + bounds, + subproblemType = IntegerType(), // helper() method returns int + solutionType = StringType(), // solution is a string, showing where characters come from S1 with parens + sol, + tslcs_definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2), StringLengthExpression(s3)))) + ) + + TSLCS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/DistinctSubsequences.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/DistinctSubsequences.scala new file mode 100644 index 00000000..b199451b --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/DistinctSubsequences.scala @@ -0,0 +1,74 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +/** + * Name: Distinct Subsequences + * Description: + * Given two strings s1 and s2, return the number of distinct subsequences of s1 which equals s2. + * + * Example: + * s = "rabbbit", t = "rabbit" + * result = 3 (three ways to pick the three b's) + * + * Recurrence: + * P(i, 0) = 1 (empty t is always a subsequence) + * P(0, j) = 0, j > 0 (non-empty t cannot be a subsequence of empty s) + * P(i, j) = P(i-1, j) if s[i-1] != t[j-1] + * P(i, j) = P(i-1, j) + P(i-1, j-1) if s[i-1] == t[j-1] + */ + +// todo: identify root cause of test case error +class DistinctSubsequences { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + val matchCase = SubproblemExpression(Seq(r - one, c - one)) + SubproblemExpression(Seq(r - one, c)) + + val noMatchCase = ExpressionDefinition( + SubproblemExpression(Seq(r - one, c)) + ) + + val subproblemTraversal = IfThenElseDefinition( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + ExpressionStatement(matchCase), + noMatchCase + ) + + val baseCase2 = IfThenElseDefinition( + c == zero, + ExpressionStatement(one), + subproblemTraversal + ) + + val definition = IfThenElseDefinition( + r == zero, + ExpressionStatement(zero), + baseCase2 + ) + + val DS: EnhancedModel = new EnhancedModel( + "DistinctSubsequences", + List(s1, s2), + subproblemType = IntegerType(), + solutionType = IntegerType(), + soln, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2))) + ) + ) + + DS + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/LongestCommonSubsequence.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/LongestCommonSubsequence.scala new file mode 100644 index 00000000..fd87bbb8 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/LongestCommonSubsequence.scala @@ -0,0 +1,48 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +class LongestCommonSubsequence { + def model:EnhancedModel = { + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order=Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + val subproblemTraversal = IfThenElseDefinition( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + ExpressionStatement(SubproblemExpression(Seq(r - one, c - one)) + one), + ExpressionDefinition( + MaxExpression( + SubproblemExpression(Seq(r, c - one)), + SubproblemExpression(Seq(r - one, c)) + ) + ) + ) + + val definition = IfThenElseDefinition( + r == zero || c == zero, + ExpressionStatement(zero), + subproblemTraversal + ) + + val LCS: EnhancedModel = new EnhancedModel( + "LongestCommonSubsequence", + List(s1, s2), + subproblemType = IntegerType(), + solutionType = StringType(), + soln, + definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2)))) + ) + + LCS + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/MinEditDistance.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/MinEditDistance.scala new file mode 100644 index 00000000..8f0202e8 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/MinEditDistance.scala @@ -0,0 +1,59 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +class MinEditDistance { + def model: EnhancedModel = { + { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + val subproblemTraversal = IfThenElseDefinition( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + ExpressionStatement(SubproblemExpression(Seq(r - one, c - one))), + ExpressionDefinition( + MinExpression( + SubproblemExpression(Seq(r - one, c)), + MinExpression( + SubproblemExpression(Seq(r, c - one)), + SubproblemExpression(Seq(r - one, c - one)) + ) + ) + one + ) + ) + + val baseCase2 = IfThenElseDefinition( + r == zero, + ExpressionStatement(r), + subproblemTraversal + ) + + val definition = IfThenElseDefinition( + c == zero, + ExpressionStatement(c), + baseCase2 + ) + + val MED: EnhancedModel = new EnhancedModel( + "MinEditDistance", + List(s1, s2), + subproblemType = IntegerType(), + solutionType = StringType(), + soln, + definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2)))) + ) + + MED + } + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/MinimumAsciiDelete.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/MinimumAsciiDelete.scala new file mode 100644 index 00000000..08cd948a --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/MinimumAsciiDelete.scala @@ -0,0 +1,85 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +// todo: add ascii implementation in engine + +/** + * Name: Minimum Delete Sum + * Description: + * Given two strings s1 and s2, return the lowest ASCII sum of deleted characters + * to make them equal. + * + * Example: + * s1 = "sea", s2 = "eat" + * result = 231 (delete 's' (115) from s1 and 't' (116) from s2) + * + * Recurrence: + * P(0, 0) = 0 + * P(i, 0) = P(i-1, 0) + ascii(s1[i-1]) delete all of s1 prefix + * P(0, j) = P(0, j-1) + ascii(s2[j-1]) delete all of s2 prefix + * P(i, j) = P(i-1, j-1) if s1[i-1] == s2[j-1] + * P(i, j) = min(P(i-1,j) + ascii(s1[i-1]), P(i,j-1) + ascii(s2[j-1])) otherwise + * + */ +class MinimumAsciiDelete { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + val asciiS1 = CharToAsciiExpression(CharAtExpression(s1, r - one)) + val asciiS2 = CharToAsciiExpression(CharAtExpression(s2, c - one)) + + val subproblemTraversal = IfThenElseDefinition( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + ExpressionStatement(SubproblemExpression(Seq(r - one, c - one))), + ExpressionDefinition( + MinExpression( + SubproblemExpression(Seq(r - one, c)) + asciiS1, + SubproblemExpression(Seq(r, c - one)) + asciiS2 + ) + ) + ) + + val baseCase2 = IfThenElseDefinition( + r == zero, + ExpressionStatement(SubproblemExpression(Seq(zero, c - one)) + asciiS2), + subproblemTraversal + ) + + val baseCase1 = IfThenElseDefinition( + c == zero, + ExpressionStatement(SubproblemExpression(Seq(r - one, zero)) + asciiS1), + baseCase2 + ) + + val definition = IfThenElseDefinition( + r == zero && c == zero, + ExpressionStatement(zero), + baseCase1 + ) + + val MDS: EnhancedModel = new EnhancedModel( + "MinimumDeleteSum", + List(s1, s2), + subproblemType = IntegerType(), + solutionType = IntegerType(), + soln, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2))) + ) + ) + + MDS + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/NeedlemanWunschSequenceAlignment.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/NeedlemanWunschSequenceAlignment.scala new file mode 100644 index 00000000..89a2613e --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/NeedlemanWunschSequenceAlignment.scala @@ -0,0 +1,64 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +// todo: identify root cause of test case error +class NeedlemanWunschSequenceAlignment { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + val matchBonus = ArgExpression(2, "matchBonus", IntegerType(), "") + val mismatchPenalty = ArgExpression(3, "mismatchPenalty", IntegerType(), "") + val gapPenalty = ArgExpression(4, "gapPenalty", IntegerType(), "") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + val score = TernaryExpression( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + matchBonus, + mismatchPenalty + ) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + val subproblemTraversal = ExpressionDefinition( + MaxExpression( + SubproblemExpression(Seq(r - one, c - one)) + score, + MaxExpression( + SubproblemExpression(Seq(r - one, c)) + gapPenalty, + SubproblemExpression(Seq(r, c - one)) + gapPenalty + ) + ) + + ) + + val baseCase2 = IfThenElseDefinition( + c == zero, + ExpressionStatement(r * gapPenalty), + subproblemTraversal + ) + + val definition = IfThenElseDefinition( + r == zero, + ExpressionStatement(c * gapPenalty), + baseCase2 + ) + + val NWSA: EnhancedModel = new EnhancedModel( + "NeedlemanWunschSequenceAlignment", + List(s1, s2, matchBonus, mismatchPenalty, gapPenalty), + subproblemType = IntegerType(), + solutionType = StringType(), + soln, + definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2)))) + ) + + NWSA + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/ShortestCommonSupersequence.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/ShortestCommonSupersequence.scala new file mode 100644 index 00000000..81f5e4ab --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/ShortestCommonSupersequence.scala @@ -0,0 +1,86 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +/** + * Name: Shortest Common Supersequence + * Description: + * Given two strings s1 and s2, find the length of the shortest string + * that has both s1 and s2 as subsequences. + * + * Example: + * s1 = "abac", s2 = "cab" + * result = 5 ("cabac") + * + * Recurrence: + * P(0, 0) = 0 + * P(i, 0) = i take all of s1 prefix + * P(0, j) = j take all of s2 prefix + * P(i, j) = P(i-1, j-1) + 1 if s1[i-1] == s2[j-1] + * P(i, j) = min(P(i-1,j), P(i,j-1)) + 1 otherwise + */ + +// todo: identify root cause of test case error +class ShortestCommonSupersequence { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val s1 = ArgExpression(0, "s1", StringType(), "r") + val s2 = ArgExpression(1, "s2", StringType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(s1), StringLengthExpression(s1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(s2), StringLengthExpression(s2) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + // characters match: include once, inherit diagonal + // no match: take the shorter option and add 1 + val subproblemTraversal = IfThenElseDefinition( + CharAtExpression(s1, r - one) == CharAtExpression(s2, c - one), + ExpressionStatement(SubproblemExpression(Seq(r - one, c - one)) + one), + ExpressionDefinition( + MinExpression( + SubproblemExpression(Seq(r - one, c)), + SubproblemExpression(Seq(r, c - one)) + ) + one + ) + ) + + // P(0, j) = j: take all of s2 prefix + val baseCase2 = IfThenElseDefinition( + r == zero, + ExpressionStatement(c), + subproblemTraversal + ) + + // P(i, 0) = i: take all of s1 prefix + val baseCase1 = IfThenElseDefinition( + c == zero, + ExpressionStatement(r), + baseCase2 + ) + + // P(0, 0) = 0 + val definition = IfThenElseDefinition( + r == zero && c == zero, + ExpressionStatement(zero), + baseCase1 + ) + + val SCS: EnhancedModel = new EnhancedModel( + "ShortestCommonSupersequence", + List(s1, s2), + subproblemType = IntegerType(), + solutionType = StringType(), + soln, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(StringLengthExpression(s1), StringLengthExpression(s2))) + ) + ) + + SCS + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/UncrossedLines.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/UncrossedLines.scala new file mode 100644 index 00000000..11f94911 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/UncrossedLines.scala @@ -0,0 +1,48 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +class UncrossedLines { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + + val nums1 = ArgExpression(0, "nums1", IntegerArrayType(), "r") + val nums2 = ArgExpression(1, "nums2", IntegerArrayType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= ArrayLengthExpression(nums1), ArrayLengthExpression(nums1) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= ArrayLengthExpression(nums2), ArrayLengthExpression(nums2) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = IntegerType()) + + val subproblemTraversal = IfThenElseDefinition( + ArrayElementExpression(nums1, r - one) == ArrayElementExpression(nums2, c - one), + ExpressionStatement(SubproblemExpression(Seq(r - one, c - one)) + one), + ExpressionDefinition( + MaxExpression( + SubproblemExpression(Seq(r, c - one)), + SubproblemExpression(Seq(r - one, c)) + ) + ) + ) + + val definition = IfThenElseDefinition( + r == zero || c == zero, + ExpressionStatement(zero), + subproblemTraversal + ) + + val UL: EnhancedModel = new EnhancedModel( + "UncrossedLines", + List(nums1, nums2), + subproblemType = IntegerType(), + solutionType = IntegerType(), + soln, + definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(ArrayLengthExpression(nums1), ArrayLengthExpression(nums2)))) + ) + + UL + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/WildcardPatternMatching.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/WildcardPatternMatching.scala new file mode 100644 index 00000000..7dac1db6 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/WildcardPatternMatching.scala @@ -0,0 +1,100 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +/** + * Name: Wildcard Pattern Matching + * Description: + * Given strings txt and pat, return whether pat matches txt. + * '?' matches any single character. + * '*' matches any sequence of characters (including empty). + * + * Recurrence: + * P(0, 0) = true + * P(0, j) = (pat[j-1] == '*') && P(0, j-1) only a run of '*'s can match empty txt + * P(i, 0) = false non-empty pattern can't match empty txt (unless all '*') + * P(i, j) = P(i-1, j-1) if pat[j-1] == '?' or txt[i-1] == pat[j-1] + * P(i, j) = P(i-1, j) || P(i, j-1) if pat[j-1] == '*' + * P(i, j) = false otherwise + */ + +// todo: identify root cause of test case error +class WildcardPatternMatching { + def model: EnhancedModel = { + val zero = LiteralInt(0) + val one = LiteralInt(1) + val star = LiteralChar('*') + val quest = LiteralChar('?') + + val txt = ArgExpression(0, "txt", StringType(), "r") + val pat = ArgExpression(1, "pat", StringType(), "c") + + val r: HelperExpression = HelperExpression("r", zero, SelfExpression("r") <= StringLengthExpression(txt), StringLengthExpression(txt) + one) + val c: HelperExpression = HelperExpression("c", zero, SelfExpression("c") <= StringLengthExpression(pat), StringLengthExpression(pat) + one) + + val helpers = Map("r" -> r, "c" -> c) + val soln = SubproblemInvocation(order = Seq("r", "c"), helpers = helpers, returnType = BooleanType()) + + val patChar = CharAtExpression(pat, c - one) + val txtChar = CharAtExpression(txt, r - one) + + val isStar = patChar == star + val isQuest = patChar == quest + val charsMatch = txtChar == patChar + + // P(i,j) when pat[j-1] == '*': match empty (advance pat) or consume txt char + val starCase = OrExpression( + SubproblemExpression(Seq(r - one, c)), // '*' consumes one txt char + SubproblemExpression(Seq(r, c - one)) // '*' matches empty + ) + + // P(i,j) when pat[j-1] == '?' or chars match: inherit diagonal + val matchCase = ExpressionDefinition(SubproblemExpression(Seq(r - one, c - one))) + + // P(i,j) general: star, match/'?', or false + val subproblemTraversal = IfThenElseDefinition( + isStar, + ExpressionStatement(starCase), + IfThenElseDefinition( + isQuest || charsMatch, + ExpressionStatement(SubproblemExpression(Seq(r - one, c - one))), + ExpressionDefinition(LiteralBoolean(false)) + ) + ) + + // P(0, j) = (pat[j-1] == '*') && P(0, j-1) + val baseRow = IfThenElseDefinition( + r == zero, + ExpressionStatement(isStar && SubproblemExpression(Seq(zero, c - one))), + subproblemTraversal + ) + + // P(i, 0) = false (non-empty txt, empty pat) + val baseCol = IfThenElseDefinition( + c == zero, + ExpressionStatement(LiteralBoolean(false)), + baseRow + ) + + // P(0, 0) = true + val definition = IfThenElseDefinition( + r == zero && c == zero, + ExpressionStatement(LiteralBoolean(true)), + baseCol + ) + + val WPM: EnhancedModel = new EnhancedModel( + "WildcardPatternMatching", + List(txt, pat), + subproblemType = BooleanType(), + solutionType = BooleanType(), + soln, + definition, + answer = ReturnExpressionDefinition( + SubproblemExpression(Seq(StringLengthExpression(txt), StringLengthExpression(pat))) + ) + ) + + WPM + } +} \ No newline at end of file diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/WordBreak.scala b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/WordBreak.scala new file mode 100644 index 00000000..a5bd3e65 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/enhancedModels/twoSequences/WordBreak.scala @@ -0,0 +1,57 @@ +package org.combinators.models.enhancedModels.twoSequences + +import org.combinators.models._ + +/** + * Name: Word Break + * Description: + * Given a string s and y a dictionary of n words dictionary, check if + * s can be segmented into a sequence of valid words from the dictionary, separated by spaces. + * + * BROKEN. Will only work when you can support validating that a raw array contains a specific value + */ +@deprecated(message = "BROKEN. Will only work when possible to add code to confirm a string is a member of an array") +class WordBreak { + + def model: EnhancedModel = { + val zero: LiteralInt = LiteralInt(0) + val one: LiteralInt = LiteralInt(1) + val falseLit = LiteralBoolean(false) + + val s = ArgExpression(0, "s", StringType(), "i") + val dict = ArgExpression(1, "dict", StringArrayType(), "w") + + val bound = List(s, dict) + + val i: HelperExpression = HelperExpression("i", zero, SelfExpression("i") <= StringLengthExpression(s), StringLengthExpression(s) + one) + + val helperTable = Map("i" -> i) + val sol_dt = SubproblemInvocation(Seq("i"), helpers = helperTable) + + // Future Work: Consider adding an IteratorDefinition that shortcircuits definition of a subproblem after iterating for + // various reasons. Works easily in top down (just return) but not so much in bottom up (might not have ability to break) + +// val iter = IteratorDefinition("w", zero, SelfExpression("w") < ArrayLengthExpression(dict), +// EqualExpression(SubStringExpression(s, i, i + StringLengthExpression(ArrayElementExpression(dict, SelfExpression("w")))), +// ArrayElementExpression(dict, SelfExpression("w")), StringType()) +// , SelfExpression("w") + one) +// val start = i - StringLengthExpression(ArrayElementExpression(dict, SelfExpression("w"))) + + // TO DO: THIS IS NOT CORRECT. You need to confirm substring exists within dict + val dt_definition = IfThenElseDefinition(i == zero, ExpressionStatement(falseLit), + ExpressionDefinition(EqualExpression(s, SubStringExpression(s, i - one, i), StringType())) + + ) + + val WordBreak = new EnhancedModel("WordBreak", + bound, + subproblemType = BooleanType(), // helper method is an int + solutionType = StringType(), // solution is a string + sol_dt, + dt_definition, + answer = ReturnExpressionDefinition(SubproblemExpression(Seq(StringLengthExpression(s)))) + ) + + WordBreak + } +} diff --git a/dynamicProgramming/src/main/scala/org/combinators/models/original/Model.scala b/dynamicProgramming/src/main/scala/org/combinators/models/original/Model.scala new file mode 100644 index 00000000..da332597 --- /dev/null +++ b/dynamicProgramming/src/main/scala/org/combinators/models/original/Model.scala @@ -0,0 +1,18 @@ +package org.combinators.models.original + +import org.combinators.models.{ArgExpression, Expression} + +/** + * The first Model used to represent Dynamic Programming. + * + * Avoid using this original prototype, and instead use @link{EnhancedModel} + * + * @param problem Uniquely identifies the problem + * @param bounds arguments to the class constructor, containing the input + * @param cases sequence of cases that linearly describes the problem + * @param retrieveLabel future access to retrieve solution generically + */ +class Model(val problem:String, + val bounds: List[ArgExpression], + val cases: List[(Option[Expression], Expression)], + val retrieveLabel: String = "take sub-solution") diff --git a/helloworld/src/main/scala/org/combinators/Modeling.scala b/helloworld/src/main/scala/org/combinators/Modeling.scala deleted file mode 100644 index 11a34954..00000000 --- a/helloworld/src/main/scala/org/combinators/Modeling.scala +++ /dev/null @@ -1,256 +0,0 @@ -package org.combinators - -import com.github.javaparser.ast.expr.DoubleLiteralExpr -import org.combinators.ep.domain.abstractions.TypeRep -import org.combinators.ep.generator.Command.Generator -import org.combinators.ep.generator.NameProvider -import org.combinators.ep.generator.paradigm.{AnyParadigm, ObjectOriented} -import org.combinators.ep.generator.paradigm.ffi.{Arithmetic, Assertions, Booleans, Equality, RealArithmetic} - -// Expression Tree -sealed abstract class Condition(val label:String) - -final case class True() extends Condition(label = "true") -final case class False() extends Condition(label = "false") - -final case class LT(left:Formula, right:Formula) extends Condition(label = "lt") -final case class LE(left:Formula, right:Formula) extends Condition(label = "le") - -final case class Not(inner:Condition) extends Condition(label = "not") -final case class And(left:Condition, right:Condition) extends Condition(label = "and") -final case class Or(left:Condition, right:Condition) extends Condition(label = "or") - -// Operations -abstract class Formula(val label:String) -case class ConstantFormula(value:Double, actualType:TypeRep) extends Formula(label="const") -case class VariableFormula(name:String, actualType:TypeRep) extends Formula(label="var") -final case class Pi() extends Formula(label = "pi") -final case class Euler() extends Formula(label = "euler") - -case class DoubleToInt(inner:Formula) extends Formula("cast") - -case class Sqrt(inner:Formula) extends Formula(label = "sqrt") -case class Sin(inner:Formula) extends Formula(label = "sin") -case class Cos(inner:Formula) extends Formula(label = "cos") -case class Floor(inner:Formula) extends Formula(label = "floor") -case class Abs(inner:Formula) extends Formula(label = "abs") - -case class Add(left:Formula, right:Formula) extends Formula("add") -case class Sub(left:Formula, right:Formula) extends Formula("sub") -case class Mult(left:Formula, right:Formula) extends Formula("mult") -case class Div(left:Formula, right:Formula) extends Formula("div") -case class Mod(leftt:Formula, right:Formula) extends Formula("mod") -case class Pow(left:Formula, right:Formula) extends Formula("pow") -case class Log(left:Formula, right:Formula) extends Formula("log") - -case class UnaryFunctionCall(name:String, inner:Formula) extends Formula(label="function") -case class BinaryFunctionCall(name:String, left:Formula, right:Formula) extends Formula(label="function") - -class Structure(val conditions:Seq[(Condition, Formula)], val default:Formula) { - -} - -trait Expansion { - val paradigm: AnyParadigm - val names: NameProvider[paradigm.syntax.Name] - - val ffiArithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Int] - val ffiRealArithmetic : RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] - val ffiBooleans : Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] - val ffiAssertions : Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] - val ffiEquality : Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] - - // must be provided - def find_method_recursive(name:paradigm.syntax.Name) : Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] - def cast_double_to_int(inner:paradigm.syntax.Expression) : Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] - - - def expand(f:Formula): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - import paradigm.methodBodyCapabilities._ - - f match { - - case DoubleToInt(inner) => - for { - in <- expand(inner) - res <- cast_double_to_int(in) - } yield res - - case ConstantFormula(value, TypeRep.Int) => - for { - value <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, value.intValue()) - } yield value - - case ConstantFormula(value, TypeRep.Double) => - for { - value <- paradigm.methodBodyCapabilities.reify(TypeRep.Double, value) - } yield value - - // this works for Java. NOT for Scala - case VariableFormula(name, typeRep) => - for { - args <- getArguments() - - specific = args.filter(triple => triple._1.toString.equals(name)).head - } yield specific._3 - - case Pi() => - for { - value <- paradigm.methodBodyCapabilities.reify(TypeRep.Double, math.Pi) - } yield value - - case Euler() => - for { - value <- paradigm.methodBodyCapabilities.reify(TypeRep.Double, math.E) - } yield value - - case Sqrt(inner) => - for { - in <- expand(inner) - value <- ffiRealArithmetic.realArithmeticCapabilities.sqrt(in) - } yield value - - case Sin(inner) => - for { - in <- expand(inner) - value <- ffiRealArithmetic.realArithmeticCapabilities.sin(in) - } yield value - - case Cos(inner) => - for { - in <- expand(inner) - value <- ffiRealArithmetic.realArithmeticCapabilities.cos(in) - } yield value - - case Floor(inner) => - for { - in <- expand(inner) - value <- ffiRealArithmetic.realArithmeticCapabilities.floor(in) - } yield value - - case Abs(inner) => - for { - in <- expand(inner) - value <- ffiRealArithmetic.realArithmeticCapabilities.abs(in) - } yield value - - case Add(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiArithmetic.arithmeticCapabilities.add(leftF, rightF) - } yield value - - case Sub(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiArithmetic.arithmeticCapabilities.sub(leftF, rightF) - } yield value - - case Mult(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiArithmetic.arithmeticCapabilities.mult(leftF, rightF) - } yield value - - case Div(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiArithmetic.arithmeticCapabilities.div(leftF, rightF) - } yield value - - case Mod(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiArithmetic.arithmeticCapabilities.mod(leftF, rightF) - } yield value - - case Pow(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiRealArithmetic.realArithmeticCapabilities.pow(leftF, rightF) - } yield value - - case Log(left, right) => - for { - leftF <- expand(left) - rightF <- expand(right) - value <- ffiRealArithmetic.realArithmeticCapabilities.log(leftF, rightF) - } yield value - - case UnaryFunctionCall(name, inner) => - for { - func <- find_method_recursive(names.mangle(name)) - in <- expand(inner) - fres <- apply(func, Seq(in)) - } yield fres - - case BinaryFunctionCall(name, left, right) => - for { - func <- find_method_recursive(names.mangle(name)) - leftF <- expand(left) - rightF <- expand(right) - fres <- apply(func, Seq(leftF, rightF)) - } yield fres - } - } - - def expand(cond:Condition): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - import paradigm.projectCapabilities._ - - cond match { - case True() => - for { - res <- ffiBooleans.booleanCapabilities.trueExp - } yield res - - case False() => - for { - res <- ffiBooleans.booleanCapabilities.falseExp - } yield res - - case Not(inner) => - for { - in <- expand(inner) - res <- ffiBooleans.booleanCapabilities.not(in) - } yield res - - case And(left, right) => - for { - leftExp <- expand(left) - rightExp <- expand(right) - res <- ffiBooleans.booleanCapabilities.and(Seq(leftExp, rightExp)) - } yield res - - case Or(left, right) => - for { - leftExp <- expand(left) - rightExp <- expand(right) - res <- ffiBooleans.booleanCapabilities.or(Seq(leftExp, rightExp)) - } yield res - - case LT(left, right) => - for { - leftExp <- expand(left) - rightExp <- expand(right) - res <- ffiArithmetic.arithmeticCapabilities.lt(leftExp, rightExp) - } yield res - - case LE(left, right) => - for { - leftExp <- expand(left) - rightExp <- expand(right) - res <- ffiArithmetic.arithmeticCapabilities.le(leftExp, rightExp) - } yield res - - case _ => ??? - } - } - - -} \ No newline at end of file diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainRecursiveVariableScala.scala b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainRecursiveVariableScala.scala index f41dfe9e..57d07aca 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainRecursiveVariableScala.scala +++ b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainRecursiveVariableScala.scala @@ -40,10 +40,14 @@ class FibonacciRecursiveVariableMainScala { val ast: FullAST = new FinalBaseAST with FinalNameProviderAST with FinalArithmeticAST + with FinalArraysAST with FinalAssertionsAST with FinalBooleanAST + with FinalConsoleAST + with FinalExceptionsAST with FinalEqualsAST with FinalListsAST + with FinalMapsAST with FinalOperatorExpressionsAST with FinalRealArithmeticOpsAST with FinalStringAST { diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainScala.scala b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainScala.scala index 944e18e9..eddc20c5 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainScala.scala +++ b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainScala.scala @@ -33,10 +33,14 @@ class FibonacciMainScala { val ast: FullAST = new FinalBaseAST with FinalNameProviderAST with FinalArithmeticAST + with FinalArraysAST with FinalAssertionsAST with FinalBooleanAST + with FinalConsoleAST + with FinalExceptionsAST with FinalEqualsAST with FinalListsAST + with FinalMapsAST with FinalOperatorExpressionsAST with FinalRealArithmeticOpsAST with FinalStringAST { diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainWithLucasScala.scala b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainWithLucasScala.scala index bae28ab4..db78201c 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainWithLucasScala.scala +++ b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciMainWithLucasScala.scala @@ -8,7 +8,7 @@ package org.combinators.fibonacci * advantage of an identity with the Lucas Numbers: * * Lucas(n) = Fib(n-1) + F(n+1) for n > 1 - * Fib(x+y) = [(Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 + * Fib(x+y) = [Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 package fibonacci def fib(n: Int): Int = { @@ -70,10 +70,14 @@ class FibonacciMainWithLucasScala { val ast: FullAST = new FinalBaseAST with FinalNameProviderAST with FinalArithmeticAST + with FinalArraysAST with FinalAssertionsAST with FinalBooleanAST + with FinalConsoleAST + with FinalExceptionsAST with FinalEqualsAST with FinalListsAST + with FinalMapsAST with FinalOperatorExpressionsAST with FinalRealArithmeticOpsAST with FinalStringAST { diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciScala.scala b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciScala.scala index 452d4793..6bbbfa6e 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciScala.scala +++ b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciScala.scala @@ -22,10 +22,12 @@ def fib(n: Int): Int = { import cats.effect.{ExitCode, IO, IOApp} import org.apache.commons.io.FileUtils -import org.combinators.ep.generator.FileWithPathPersistable._ -import org.combinators.ep.generator.{FileWithPath, FileWithPathPersistable} - -import org.combinators.ep.language.scala.codegen.CodeGenerator +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import org.combinators.ep.language.scala.ast.* +import org.combinators.ep.language.scala.ast.ffi.{FinalArithmeticAST, FinalArraysAST, FinalAssertionsAST, FinalBooleanAST, FinalConsoleAST, FinalEqualsAST, FinalExceptionsAST, FinalListsAST, FinalMapsAST, FinalOperatorExpressionsAST, FinalRealArithmeticOpsAST, FinalStringAST} +import org.combinators.ep.language.scala.codegen.{CodeGenerator, FullAST} +import org.combinators.cogen.FileWithPathPersistable +import org.combinators.cogen.FileWithPathPersistable.fileWithPathPersistable import java.nio.file.{Path, Paths} @@ -36,10 +38,14 @@ class FibonacciScala { val ast: FullAST = new FinalBaseAST with FinalNameProviderAST with FinalArithmeticAST + with FinalArraysAST with FinalAssertionsAST with FinalBooleanAST + with FinalConsoleAST + with FinalExceptionsAST with FinalEqualsAST with FinalListsAST + with FinalMapsAST with FinalOperatorExpressionsAST with FinalRealArithmeticOpsAST with FinalStringAST { @@ -52,7 +58,7 @@ class FibonacciScala { // TODO: Need to add generator.functional val fibonacciApproach = FibonacciProvider[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.functional, generator.functionalControl.functionalControlInMethods, generator.ints.arithmeticInMethods, generator.assertions.assertionsInMethods, generator.equality.equalsInMethods) - val persistable: Aux[FileWithPath] = FileWithPathPersistable[FileWithPath] + val persistable: FileWithPathPersistable.Aux[FileWithPath] = FileWithPathPersistable[FileWithPath] def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { //FIX: diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucas.scala b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucas.scala index a4e88d41..0a0986f1 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucas.scala +++ b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucas.scala @@ -11,15 +11,15 @@ import org.combinators.cogen.{AbstractSyntax, Command, NameProvider} * Take advantage of observation that: * * Lucas(n) = Fib(n-1) + F(n+1) for n > 1 - * Fib(x+y) = [(Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 + * Fib(x+y) = [Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 * * With this you can declare * * n1 = floor(n/2) * n2 = n - n1 - * Fib(n) = [(Fib(n1)*Lucas(n2) + Fib(n2)*Locas(n1)] / 2 + * Fib(n) = [Fib(n1)*Lucas(n2) + Fib(n2)*Locas(n1)] / 2 * - * And the resulting speed up is quite impressive + * And the resulting speed-up is quite impressive */ trait FibonacciWithLucas { val paradigm: AnyParadigm diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucasMainJava.scala b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucasMainJava.scala index 95971158..8740e0c6 100644 --- a/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucasMainJava.scala +++ b/helloworld/src/main/scala/org/combinators/fibonacci/FibonacciWithLucasMainJava.scala @@ -8,7 +8,7 @@ package org.combinators.fibonacci * advantage of an identity with the Lucas Numbers: * * Lucas(n) = Fib(n-1) + F(n+1) for n > 1 - * Fib(x+y) = [(Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 + * Fib(x+y) = [Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 ackage fibonacci; diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursion.scala b/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursion.scala deleted file mode 100644 index bb820f7d..00000000 --- a/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursion.scala +++ /dev/null @@ -1,412 +0,0 @@ -package org.combinators.fibonacci - -/** - * Not yet completed. - * - * This effort will eventually yield the ability to generate a recursive function simply by - * identifying (a) the base cases; and (b) the recursive call structure. - */ - -import org.combinators._ -import org.combinators.ep.domain.abstractions.TypeRep -import org.combinators.ep.generator.Command.Generator -import org.combinators.ep.generator.paradigm.ffi.{Arithmetic, Assertions, Booleans, Equality, RealArithmetic} -import org.combinators.ep.generator.paradigm.{AnyParadigm, Functional, ObjectOriented, control} -import org.combinators.ep.generator.{AbstractSyntax, Command, NameProvider} - -/*** - -Want to get to this.... memoization - -package fibonacci; -import java.util.*; - -public class Fib { - Hashtable results = new Hashtable<>(); - public Integer fib(Integer n) { - if (results.containsKey(n)) { return results.get(n); } - if ((n <= 0)) { - return 0; - } else if ((n <= 1)) { - return 1; - } else { - int stored = (this.fib((n - 1)) + this.fib((n - 2))); - results.put(n, stored); - return stored; - } - } -} - - - - - * @param label - */ - - -trait GenericRecursion extends Expansion { - val paradigm: AnyParadigm - val names: NameProvider[paradigm.syntax.Name] - - val ffiArithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Int] - val ffiRealArithmetic : RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] - val ffiBooleans : Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] - val ffiAssertions : Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] - val ffiEquality : Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] - - val nminus1 = Sub(VariableFormula("n", TypeRep.Int), ConstantFormula(1, TypeRep.Int)) - val nminus2 = Sub(VariableFormula("n", TypeRep.Int), ConstantFormula(2, TypeRep.Int)) - - val cond0 = LE(VariableFormula("n", TypeRep.Int), ConstantFormula(0, TypeRep.Int)) - val cond1 = LE(VariableFormula("n", TypeRep.Int), ConstantFormula(1, TypeRep.Int)) - val fib_n_minus_one = UnaryFunctionCall(fibRecursive, nminus1) - val fib_n_minus_two = UnaryFunctionCall(fibRecursive, nminus2) - val add = Add(fib_n_minus_one, fib_n_minus_two) - - // names.mangle(...) - lazy val fibRecursive:String = "fib" - lazy val fibName:String = "fib_lucas" - lazy val lucasName:String = "lucas" - - lazy val testFibName:paradigm.syntax.Name = names.mangle("fibTest") - lazy val nName:paradigm.syntax.Name = names.mangle("n") - - type IfBlockType - - def if_then_else(cond: paradigm.syntax.Expression, - ifBlock: Generator[paradigm.MethodBodyContext, IfBlockType], - ifElseBlocks: Seq[(paradigm.syntax.Expression, Generator[paradigm.MethodBodyContext, IfBlockType])], - elseBlock: Generator[paradigm.MethodBodyContext, IfBlockType]): - Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] - - def cast_double_to_int(inner:paradigm.syntax.Expression) : Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] - - def find_method_recursive(name:paradigm.syntax.Name) : Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] - - // used for tests - def find_method(name:paradigm.syntax.Name) : Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] - - // add method (in OO this would require construction of a class first...) - def add_methods(methods:Map[String, Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]]]): - Generator[paradigm.CompilationUnitContext, Unit] - - def return_in_if(toReturn:Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression]): Generator[paradigm.MethodBodyContext, IfBlockType] - - def make_fibonacci(): Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] = { - import paradigm.methodBodyCapabilities._ - - val frame = new Structure( - conditions = Seq((cond0, ConstantFormula(0, TypeRep.Int)), (cond1, ConstantFormula(1, TypeRep.Int))), - default = add) - - for { - // NEED to do first so these are arguments ready - intType <- toTargetLanguageType(TypeRep.Int) - - _ <- paradigm.methodBodyCapabilities.setParameters(Seq((nName, intType))) - _ <- paradigm.methodBodyCapabilities.setReturnType(intType) - - res <- finish(frame) - } yield res - } - - def finish(frame:Structure): Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] = { - import org.combinators.ep.generator.paradigm.AnyParadigm.syntax.forEach - - for { - condition_sequence <- frame.conditions - .foldLeft(Command.lift[paradigm.MethodBodyContext,Seq[(paradigm.syntax.Expression, Generator[paradigm.MethodBodyContext, IfBlockType])]](Seq.empty)) - { case (result,cond) => - for { - fc <- expand(cond._1) - ff <- expand(cond._2) - old_result <- result - } yield old_result :+ (fc,return_in_if(Command.lift(ff))) - } - - // the default recursive case is isolated - fdefault <- Command.lift(expand(frame.default)) - - res <- if_then_else(condition_sequence.head._1, - condition_sequence.head._2, - condition_sequence.tail, - return_in_if(fdefault)) - - } yield res - } - - def make_fibonacci_with_lucas(lucas_name:String, fib_lucas_name:String): Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] = { - import paradigm.methodBodyCapabilities._ - - /** - * Take advantage of observation that: - * - * Fib(x+y) = [(Fib(x)*Lucas(y) + Fib(y)*Locas(x)] / 2 - * - * With this you can declare - * - * n1 = floor(n/2) - * n2 = n - n1 - * Fib(n) = [(Fib(n1)*Lucas(n2) + Fib(n2)*Lucas(n1)] / 2 - * - */ - val n1 = DoubleToInt(Floor(Div(VariableFormula("n", TypeRep.Int), ConstantFormula(2, TypeRep.Int)))) - val n2 = Sub(VariableFormula("n", TypeRep.Int), n1) - - val fib_n1 = UnaryFunctionCall(fib_lucas_name, n1) - val fib_n2 = UnaryFunctionCall(fib_lucas_name, n2) - val lucas_n1 = UnaryFunctionCall(lucas_name, n1) - val lucas_n2 = UnaryFunctionCall(lucas_name, n2) - - val fibRecursion = Div(Add(Mult(fib_n1, lucas_n2),Mult(fib_n2, lucas_n1)), ConstantFormula(2, TypeRep.Int)) - - val frame = new Structure( - conditions = Seq( - (cond0, ConstantFormula(0, TypeRep.Int)), - (cond1, ConstantFormula(1, TypeRep.Int)), - (LE(VariableFormula("n", TypeRep.Int), ConstantFormula(2, TypeRep.Int)), ConstantFormula(1, TypeRep.Int)), - (LE(VariableFormula("n", TypeRep.Int), ConstantFormula(3, TypeRep.Int)), ConstantFormula(2, TypeRep.Int)), - ), - default = fibRecursion - ) - - for { - // NEED to do first so these are arguments ready - intType <- toTargetLanguageType(TypeRep.Int) - - _ <- paradigm.methodBodyCapabilities.setParameters(Seq((nName, intType))) - _ <- paradigm.methodBodyCapabilities.setReturnType(intType) - - res <- finish(frame) - } yield res - } - - def make_lucas_with_fibonacci(fib_lucas_name:String): Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] = { - import paradigm.methodBodyCapabilities._ - - /** - * Take advantage of observation that: - * - * Lucas(n) = Fib(n-1) + F(n+1) for n > 1 - */ - val nplus1 = Add(VariableFormula("n", TypeRep.Int), ConstantFormula(1, TypeRep.Int)) - val fib_n_plus_one = UnaryFunctionCall(fib_lucas_name, nplus1) - val fib_n_minus_one = UnaryFunctionCall(fib_lucas_name, nminus1) - val lucasRecursion = Add(fib_n_plus_one, fib_n_minus_one) - - val frame = new Structure( - conditions = Seq( - (cond0, ConstantFormula(2, TypeRep.Int)), - (cond1, ConstantFormula(1, TypeRep.Int))), - default = lucasRecursion - ) - - for { - // NEED to do first so these are arguments ready - intType <- toTargetLanguageType(TypeRep.Int) - - _ <- paradigm.methodBodyCapabilities.setParameters(Seq((nName, intType))) - _ <- paradigm.methodBodyCapabilities.setReturnType(intType) - - res <- finish(frame) - } yield res - } - - def make_unit(): Generator[paradigm.CompilationUnitContext, Unit] = { - add_methods(Map( - fibRecursive -> make_fibonacci(), - fibName -> make_fibonacci_with_lucas(lucasName, fibName), - lucasName -> make_lucas_with_fibonacci(fibName) - )) - } - - def make_fibonacci_test(): Generator[paradigm.MethodBodyContext, Seq[paradigm.syntax.Expression]] = { - import ffiEquality.equalityCapabilities._ - import paradigm.methodBodyCapabilities._ - for { - intType <- toTargetLanguageType(TypeRep.Int) - func_straight_fib <- find_method(names.mangle(fibRecursive)) - func_lucas_fib <- find_method(names.mangle(fibName)) - - zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) - one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) - - seven <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 7) - thirteen <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 13) - twentynine <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 29) - - total = Seq((zero,zero), (one,one), (seven, thirteen)) - - tests <- total - .foldLeft(Command.lift[paradigm.MethodBodyContext,Seq[paradigm.syntax.Expression]](Seq.empty)) - { case (result,(input,actual)) => - for { - check <- apply(func_straight_fib, Seq(input)) - assertcheck <- ffiAssertions.assertionCapabilities.assertEquals(intType, check, actual) - old_result <- result // needed to "extract out the generator" - - check2 <- apply(func_lucas_fib, Seq(input)) - assertcheck2 <- ffiAssertions.assertionCapabilities.assertEquals(intType, check2, actual) - - } yield old_result :+ assertcheck :+ assertcheck2 - } - - } yield tests - } - - def make_test() : Generator[paradigm.TestContext, Unit] = { - for { - _ <- paradigm.testCapabilities.addTestCase(make_fibonacci_test(), testFibName) - } yield () - } - - def make_project(): Generator[paradigm.ProjectContext, Unit] = { - for { - _ <- paradigm.projectCapabilities.addCompilationUnit(make_unit(), names.mangle(fibRecursive)) - _ <- paradigm.projectCapabilities.addCompilationUnit(paradigm.compilationUnitCapabilities.addTestSuite(testFibName, make_test()), testFibName) - } yield () - } -} - -// below ensures we can generate both functional and imperative solutions - -object GenericRecursionProvider { - type WithParadigm[P <: AnyParadigm] = GenericRecursion { val paradigm: P } - type WithSyntax[S <: AbstractSyntax] = WithParadigm[AnyParadigm.WithSyntax[S]] - - def functional[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] - (base: P) - (nameProvider: NameProvider[base.syntax.Name], - func: Functional.WithBase[base.type], - c1: control.Functional.WithBase[base.MethodBodyContext, base.type], - c2: Arithmetic.WithBase[base.MethodBodyContext, base.type, Int], - c3: Assertions.WithBase[base.MethodBodyContext, base.type], - c4: Equality.WithBase[base.MethodBodyContext, base.type], - c5: Booleans.WithBase[base.MethodBodyContext, base.type], - c6: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double] - ) - : GenericRecursionProvider.WithParadigm[base.type] = - new GenericRecursion { - override val paradigm: base.type = base - override val names: NameProvider[paradigm.syntax.Name] = nameProvider - - override val ffiArithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Int] = c2 - override val ffiAssertions: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] = c3 - override val ffiEquality : Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] = c4 - override val ffiBooleans : Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] = c5 - override val ffiRealArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] = c6 - - override type IfBlockType = paradigm.syntax.Expression - - // nothing to do - override def cast_double_to_int(inner:paradigm.syntax.Expression): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - for { - res <- Command.lift(inner) - } yield res - } - - override def if_then_else(cond: paradigm.syntax.Expression, ifBlock: Generator[paradigm.MethodBodyContext, IfBlockType], ifElseBlocks: Seq[(paradigm.syntax.Expression, Generator[paradigm.MethodBodyContext, IfBlockType])], elseBlock: Generator[paradigm.MethodBodyContext, IfBlockType]): Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] = { - for { - res <- c1.functionalCapabilities.ifThenElse(cond, ifBlock, ifElseBlocks, elseBlock) - } yield Some(res) - } - - override def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = find_method(name) - override def find_method(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - func.methodBodyCapabilities.findMethod(Seq(name)) - } - - override def add_methods(methods: Map[String, Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]]]): Generator[paradigm.CompilationUnitContext, Unit] = { - import AnyParadigm.syntax._ - for { - _ <- forEach(methods.toList) { case (name, spec) => - func.compilationUnitCapabilities.addMethod(names.mangle(name), spec.map(x => x.get)) - } - } yield () - } - - override def return_in_if(toReturn: Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression]): Generator[paradigm.MethodBodyContext, IfBlockType] = { - toReturn - } - } - - def imperative[S <: AbstractSyntax, P <: AnyParadigm.WithSyntax[S]] - (base: P) - (nameProvider: NameProvider[base.syntax.Name], - obj: ObjectOriented.WithBase[base.type], - c1: control.Imperative.WithBase[base.MethodBodyContext, base.type], - c2: Arithmetic.WithBase[base.MethodBodyContext, base.type, Int], - c3: Assertions.WithBase[base.MethodBodyContext, base.type], - c4: Equality.WithBase[base.MethodBodyContext, base.type], - c5: Booleans.WithBase[base.MethodBodyContext, base.type], - c6: RealArithmetic.WithBase[base.MethodBodyContext, base.type, Double] - ) - : GenericRecursionProvider.WithParadigm[base.type] = - new GenericRecursion { - override val paradigm: base.type = base - override val names: NameProvider[paradigm.syntax.Name] = nameProvider - - override val ffiArithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Int] = c2 - override val ffiAssertions: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] = c3 - override val ffiEquality : Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] = c4 - override val ffiBooleans : Booleans.WithBase[paradigm.MethodBodyContext, paradigm.type] = c5 - override val ffiRealArithmetic: RealArithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Double] = c6 - - override type IfBlockType = Unit - lazy val fibClass:paradigm.syntax.Name = names.mangle("Fib") - - override def cast_double_to_int(inner:paradigm.syntax.Expression): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - import paradigm.methodBodyCapabilities._ - import obj.methodBodyCapabilities._ - for { - itype <- toTargetLanguageType(TypeRep.Int) - asInt <- castObject(itype, inner) - } yield asInt - } - - override def if_then_else(cond: paradigm.syntax.Expression, ifBlock: Generator[paradigm.MethodBodyContext, IfBlockType], ifElseBlocks: Seq[(paradigm.syntax.Expression, Generator[paradigm.MethodBodyContext, IfBlockType])], elseBlock: Generator[paradigm.MethodBodyContext, IfBlockType]): Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]] = { - for { - resultStmt <- c1.imperativeCapabilities.ifThenElse(cond, ifBlock, ifElseBlocks, Some(elseBlock)) - _ <- paradigm.methodBodyCapabilities.addBlockDefinitions(Seq(resultStmt)) - } yield None - } - - override def find_method_recursive(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - for { - self <- obj.methodBodyCapabilities.selfReference() - res <- obj.methodBodyCapabilities.getMember(self, name) - } yield res - } - - override def find_method(name: paradigm.syntax.Name): Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression] = { - for { - typ <- obj.methodBodyCapabilities.findClass(fibClass) - fib <- obj.methodBodyCapabilities.instantiateObject(typ, Seq.empty) - res <- obj.methodBodyCapabilities.getMember(fib, name) - } yield res - } - - override def add_methods(methods:Map[String, Generator[paradigm.MethodBodyContext, Option[paradigm.syntax.Expression]]]) : - Generator[paradigm.CompilationUnitContext, Unit] = { - import AnyParadigm.syntax._ - - def makeMethods(): Generator[obj.ClassContext, Unit] = { - for { - _ <- forEach(methods.toList) { case (name, spec) => - obj.classCapabilities.addMethod(names.mangle(name), spec) - } - } yield () - } - - obj.compilationUnitCapabilities.addClass(fibClass, makeMethods()) - } - - override def return_in_if(toReturn: Generator[paradigm.MethodBodyContext, paradigm.syntax.Expression]): Generator[paradigm.MethodBodyContext, IfBlockType] = { - for { - resultExp <- toReturn - resultStmt <- c1.imperativeCapabilities.returnStmt(resultExp) - _ <- paradigm.methodBodyCapabilities.addBlockDefinitions(Seq(resultStmt)) - } yield None - } - } -} diff --git a/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursionScala.scala b/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursionScala.scala deleted file mode 100644 index fce5c5b7..00000000 --- a/helloworld/src/main/scala/org/combinators/fibonacci/GenericRecursionScala.scala +++ /dev/null @@ -1,75 +0,0 @@ -package org.combinators.fibonacci - -/** - * Not yet completed. - * - * This effort will eventually yield the ability to generate a recursive function simply by - * identifying (a) the base cases; and (b) the recursive call structure. - */ - -import cats.effect.{ExitCode, IO, IOApp} -import org.apache.commons.io.FileUtils -import org.combinators.ep.generator.FileWithPathPersistable._ -import org.combinators.ep.generator.{FileWithPath, FileWithPathPersistable} -import org.combinators.ep.language.scala.codegen.CodeGenerator - -import java.nio.file.{Path, Paths} - -/** - * Takes language-independent specification of Fibonacci with Lucas and generates Scala code - */ -class GenericRecursionMainScala{ - val generator = CodeGenerator("fibonacci") - - val fibonacciApproach = GenericRecursionProvider.functional[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.functional, generator.functionalControl, generator.ints, generator.assertionsInMethod, generator.equality, generator.booleans, generator.realDoubles) - - val persistable = FileWithPathPersistable[FileWithPath] - - def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { - - val files = - () => generator.paradigm.runGenerator { - for { - _ <- generator.ints.enable() - _ <- generator.booleans.enable() - _ <- generator.strings.enable() - _ <- generator.equality.enable() - _ <- generator.assertionsInMethod.enable() - _ <- fibonacciApproach.make_project() - } yield () - } - - IO { - print("Computing Files...") - val computed = files() - println("[OK]") - if (targetDirectory.toFile.exists()) { - print(s"Cleaning Target Directory ($targetDirectory)...") - FileUtils.deleteDirectory(targetDirectory.toFile) - println("[OK]") - } - print("Persisting Files...") - computed.foreach(file => persistable.persistOverwriting(targetDirectory, file)) - println("[OK]") - } - } - - def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { - for { - _ <- directToDiskTransaction(targetDirectory) - } yield ExitCode.Success - } -} - -object GenericRecursionScalaDirectToDiskMain extends IOApp { - val targetDirectory = Paths.get("target", "fib", "scala") - print(targetDirectory) - def run(args: List[String]): IO[ExitCode] = { - for { - _ <- IO { print("Initializing Generator...") } - main <- IO { new GenericRecursionMainScala() } - _ <- IO { println("[OK]") } - result <- main.runDirectToDisc(targetDirectory) - } yield result - } -} diff --git a/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainJava.scala b/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainJava.scala index 8a49f7be..9e91afc8 100644 --- a/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainJava.scala +++ b/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainJava.scala @@ -22,7 +22,7 @@ import java.nio.file.{Path, Paths} class HelloWorldMainJava { val generator = CodeGenerator(CodeGenerator.defaultConfig.copy(boxLevel = PartiallyBoxed, targetPackage = new PackageDeclaration(ObjectOriented.fromComponents("world")))) - val helloWorldApproach = HelloWorldObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.ooParadigm, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.equalityInMethod) + val helloWorldApproach = HelloWorldObjectOrientedProvider[Syntax.default.type, generator.paradigm.type](generator.paradigm)(JavaNameProvider, generator.imperativeInMethod, generator.ooParadigm, generator.intsInMethod, generator.consoleInMethod, generator.arraysInMethod, generator.assertionsInMethod, generator.equalityInMethod, generator.mapsInMethod) val persistable: Aux[FileWithPath] = FileWithPathPersistable[FileWithPath] @@ -34,12 +34,13 @@ class HelloWorldMainJava { _ <- generator.doublesInMethod.enable() _ <- generator.intsInMethod.enable() _ <- generator.stringsInMethod.enable() - _ <- generator.listsInMethod.enable() // should be array, but this still needs to be added as an FFI + _ <- generator.listsInMethod.enable() _ <- generator.consoleInMethod.enable() _ <- generator.arraysInMethod.enable() _ <- generator.equalityInMethod.enable() _ <- generator.assertionsInMethod.enable() - + _ <- generator.mapsInMethod.enable() // needed for resolution + _ <- helloWorldApproach.implement() } yield () } diff --git a/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainScala.scala b/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainScala.scala new file mode 100644 index 00000000..b468266c --- /dev/null +++ b/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldMainScala.scala @@ -0,0 +1,99 @@ +package org.combinators.helloworld + +/** + * sbt "helloWorld/runMain org.combinators.helloworld.HelloWorldJavaDirectToDiskMain" + * + * Creates output files in target/helloworld + */ + +import cats.effect.{ExitCode, IO, IOApp} +import com.github.javaparser.ast.PackageDeclaration +import org.apache.commons.io.FileUtils +import org.combinators.cogen.{FileWithPath, FileWithPathPersistable} +import org.combinators.ep.language.scala.codegen.FullAST +import FileWithPathPersistable._ +import org.combinators.ep.language.scala.ast._ +import org.combinators.ep.language.scala.ast.ffi._ +import org.combinators.ep.language.scala.ast.{FinalBaseAST, FinalNameProviderAST} +import org.combinators.ep.language.scala.codegen.CodeGenerator +import java.nio.file.{Path, Paths} + +/** + * Eventually encode a set of subclasses/traits to be able to easily specify (a) the variation; and (b) the evolution. + */ +class HelloWorldMainScala { + val _ast: FullAST = new FinalBaseAST + with FinalNameProviderAST + with FinalArithmeticAST + with FinalArraysAST + with FinalAssertionsAST + with FinalBooleanAST + with FinalConsoleAST + with FinalExceptionsAST + with FinalEqualsAST + with FinalListsAST + with FinalMapsAST + with FinalOperatorExpressionsAST + with FinalRealArithmeticOpsAST + with FinalStringAST { + val reificationExtensions = List.empty + } + val generator: CodeGenerator[_ast.type] = CodeGenerator("dp", _ast, Set.empty) + + val helloWorldApproach = HelloWorldObjectOrientedProvider[generator.syntax.type, generator.paradigm.type](generator.paradigm)(generator.nameProvider, generator.imperative.imperativeInMethods, generator.ooParadigm, generator.ints.arithmeticInMethods, generator.console.consoleInMethods, generator.arrays.arraysInMethods, generator.assertions.assertionsInMethods, generator.equality.equalsInMethods, generator.maps.mapsInMethods) + + val persistable: Aux[FileWithPath] = FileWithPathPersistable[FileWithPath] + + def directToDiskTransaction(targetDirectory: Path): IO[Unit] = { + + val files = + () => generator.paradigm.runGenerator { + for { + _ <- generator.doubles.arithmeticInMethods.enable() + _ <- generator.ints.arithmeticInMethods.enable() + _ <- generator.strings.stringsInMethods.enable() + _ <- generator.lists.listsInMethods.enable() + _ <- generator.console.consoleInMethods.enable() + _ <- generator.arrays.arraysInMethods.enable() + _ <- generator.equality.equalsInMethods.enable() + _ <- generator.assertions.assertionsInMethods.enable() + _ <- generator.maps.mapsInMethods.enable() + + _ <- helloWorldApproach.implement() + } yield () + } + + IO { + print("Computing Files...") + val computed = files() + println("[OK]") + if (targetDirectory.toFile.exists()) { + print(s"Cleaning Target Directory ($targetDirectory)...") + FileUtils.deleteDirectory(targetDirectory.toFile) + println("[OK]") + } + print("Persisting Files...") + files().foreach(file => persistable.persistOverwriting(targetDirectory, file)) + println("[OK]") + } + } + + def runDirectToDisc(targetDirectory: Path): IO[ExitCode] = { + for { + _ <- directToDiskTransaction(targetDirectory) + } yield ExitCode.Success + } +} + +object HelloWorldScalaDirectToDiskMain extends IOApp { + val targetDirectory = Paths.get("target", "helloworld") + + def run(args: List[String]): IO[ExitCode] = { + for { + _ <- IO { print("Initializing Generator...") } + main <- IO { new HelloWorldMainScala() } + _ <- IO { println("[OK]") } + result <- main.runDirectToDisc(targetDirectory) + } yield result + } +} diff --git a/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldObjectOrientedProvider.scala b/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldObjectOrientedProvider.scala index 2f358b06..f9f56c73 100644 --- a/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldObjectOrientedProvider.scala +++ b/helloworld/src/main/scala/org/combinators/helloworld/HelloWorldObjectOrientedProvider.scala @@ -3,7 +3,7 @@ package org.combinators.helloworld import org.combinators.cogen.TypeRep import org.combinators.cogen.paradigm.{AnyParadigm, FindClass, ObjectOriented} import org.combinators.cogen.paradigm.control.Imperative -import org.combinators.cogen.paradigm.ffi.{Arrays, Assertions, Console, Equality} +import org.combinators.cogen.paradigm.ffi.{Arithmetic, Arrays, Assertions, Console, Equality, Maps} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{AbstractSyntax, Command, NameProvider, Understands} @@ -15,10 +15,14 @@ trait HelloWorldObjectOrientedProvider extends HelloWorldProvider { val ooParadigm: ObjectOriented.WithBase[paradigm.type] val names: NameProvider[paradigm.syntax.Name] val impParadigm: Imperative.WithBase[paradigm.MethodBodyContext,paradigm.type] + val ffiArithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Int] + val console: Console.WithBase[paradigm.MethodBodyContext,paradigm.type] val array: Arrays.WithBase[paradigm.MethodBodyContext,paradigm.type] val asserts: Assertions.WithBase[paradigm.MethodBodyContext, paradigm.type] val eqls: Equality.WithBase[paradigm.MethodBodyContext, paradigm.type] + val maps: Maps.WithBase[paradigm.MethodBodyContext, paradigm.type] + import paradigm._ import syntax._ import ooParadigm._ @@ -57,8 +61,8 @@ trait HelloWorldObjectOrientedProvider extends HelloWorldProvider { for { stringType <- toTargetLanguageType(TypeRep.String) - - _ <- setParameters(Seq((names.mangle(fieldName),stringType))) + paramName <- freshName(names.mangle(fieldName)) // make sure to create a unique name for param, to avoid name clashes with field + _ <- setParameters(Seq((paramName,stringType))) args <- getArguments() _ <- initializeField(names.mangle(fieldName), args.head._3) @@ -108,25 +112,67 @@ trait HelloWorldObjectOrientedProvider extends HelloWorldProvider { import paradigm.methodBodyCapabilities._ import impParadigm.imperativeCapabilities._ + + for { _ <- makeStaticSignature() worldType <- findClass(names.mangle("World")) _ <- resolveAndAddImport(worldType) args <- getArguments() zero <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 0) - msg <- array.arrayCapabilities.get(args.head._3, zero) + one <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 1) + // msg <- array.arrayCapabilities.get(args.head._3, Seq(zero)) - res <- instantiateObject(worldType, Seq(msg)) - fname <- freshName(names.mangle("msg")) // be sure to unpack since this has a side effect on the context.... - fvar <- declareVar(fname, worldType, Some(res)) + // res <- instantiateObject(worldType, Seq(msg)) + // fname <- freshName(names.mangle("msg")) // be sure to unpack since this has a side effect on the context.... + // fvar <- declareVar(fname, worldType, Some(res)) - msgMethod <- getMember(fvar, names.mangle(getter(message))) - result <- apply(msgMethod, Seq.empty) - output <- console.consoleCapabilities.print(result) - le <- liftExpression(output) - _ <- addBlockDefinitions(Seq(le)) + // msgMethod <- getMember(fvar, names.mangle(getter(message))) + // result <- apply(msgMethod, Seq.empty) + // output <- console.consoleCapabilities.print(result) + // le <- liftExpression(output) + // _ <- addBlockDefinitions(Seq(le)) - } yield Some(res) + // array example + intType <- toTargetLanguageType(TypeRep.Int) + arr1Type <- toTargetLanguageType(TypeRep.Array(TypeRep.Int)) + arr2Type <- toTargetLanguageType(TypeRep.Array(TypeRep.Array(TypeRep.Int))) + arname <- freshName(names.mangle("ar")) + + two <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 2) + three <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 3) + initial <- array.arrayCapabilities.create(intType, Seq(two, three), None) + A <- declareVar(arname, arr2Type, Some(initial)) + + // now set individual values + setInst1 <- array.arrayCapabilities.set(A, Seq(zero, one), three) // A[0][1] = 3 + setStmt1 <- impParadigm.imperativeCapabilities.liftExpression(setInst1) + + len1 <- array.arrayCapabilities.length(A, Seq.empty) // first dimension + len2 <- array.arrayCapabilities.length(A, Seq(zero)) // 2nd dimension + len1Sub1 <- ffiArithmetic.arithmeticCapabilities.sub(len1, one) + len2Sub1 <- ffiArithmetic.arithmeticCapabilities.sub(len2, one) + setInst2 <- array.arrayCapabilities.set(A, Seq(len1Sub1, len2Sub1), two) // A[A.length-1][A[0].length-1] = 2 + setStmt2 <- impParadigm.imperativeCapabilities.liftExpression(setInst2) + _ <- addBlockDefinitions(Seq(setStmt1, setStmt2)) + + // showcase maps + stringType <- toTargetLanguageType(TypeRep.String) + initialMap <- maps.mapCapabilities.create(stringType, intType) + mapType <- toTargetLanguageType(TypeRep.Map(TypeRep.String, TypeRep.Int)) + mapVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("myMap"), mapType, Some(initialMap)) + + expr1 <- paradigm.methodBodyCapabilities.reify(TypeRep.Map(TypeRep.String,TypeRep.Int), Map[String,Int]("hello" -> 42) ) + mapVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("myMap2"), mapType, Some(expr1)) + + // put something + newKey <- paradigm.methodBodyCapabilities.reify(TypeRep.String, "there") + newValue <- paradigm.methodBodyCapabilities.reify(TypeRep.Int, 88) + + expr2 <- maps.mapCapabilities.put(mapVar, stringType, intType, newKey, newValue) + mapVar <- impParadigm.imperativeCapabilities.declareVar(names.mangle("myMap3"), mapType, Some(expr2)) + + } yield None // Some(res) } def makeMainClass(clazzName:String): Generator[ProjectContext, Unit] = { @@ -195,10 +241,12 @@ object HelloWorldObjectOrientedProvider { (nameProvider: NameProvider[base.syntax.Name], imp: Imperative.WithBase[base.MethodBodyContext, base.type], oo: ObjectOriented.WithBase[base.type], + ffi1: Arithmetic.WithBase[base.MethodBodyContext, base.type, Int], con: Console.WithBase[base.MethodBodyContext, base.type], arr: Arrays.WithBase[base.MethodBodyContext, base.type], assertsIn: Assertions.WithBase[base.MethodBodyContext, base.type], - eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type] + eqlsIn: Equality.WithBase[base.MethodBodyContext, base.type], + mapsIn: Maps.WithBase[base.MethodBodyContext, base.type] ) : HelloWorldObjectOrientedProvider.WithParadigm[base.type] = new HelloWorldObjectOrientedProvider { @@ -206,9 +254,12 @@ object HelloWorldObjectOrientedProvider { val impParadigm: imp.type = imp override val names: NameProvider[paradigm.syntax.Name] = nameProvider override val ooParadigm: ObjectOriented.WithBase[paradigm.type] = oo + override val ffiArithmetic: Arithmetic.WithBase[paradigm.MethodBodyContext, paradigm.type, Int] = ffi1 + override val console: Console.WithBase[base.MethodBodyContext, paradigm.type] = con override val array: Arrays.WithBase[base.MethodBodyContext, paradigm.type] = arr override val asserts: Assertions.WithBase[base.MethodBodyContext, paradigm.type] = assertsIn override val eqls: Equality.WithBase[base.MethodBodyContext, paradigm.type] = eqlsIn + override val maps: Maps.WithBase[base.MethodBodyContext, paradigm.type] = mapsIn } } diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AbstractSyntax.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AbstractSyntax.scala index 2c2ae517..54c80fa5 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AbstractSyntax.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AbstractSyntax.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.language.inbetween.any - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.any /*DI:LI:AI*/ import org.combinators.cogen.AbstractSyntax as AS diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyAST.scala index ce0372b5..6d6ffc24 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.any +package org.combinators.ep.language.inbetween.any /*DI:LI:AI*/ import org.combinators.cogen.{FileWithPath, TypeRep} import org.combinators.cogen.Command.Generator diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyParadigm.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyParadigm.scala index a060ff6e..7c19b1ca 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyParadigm.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/any/AnyParadigm.scala @@ -1,9 +1,7 @@ -package org.combinators.ep.language.inbetween.any - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.any /*DI:LI:AI*/ import org.combinators.cogen.TypeRep -import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddCompilationUnit, AddCustomFile, AddImport, AddMethod, AddTestCase, AddTestSuite, AddTypeLookup, Apply, Debug, FreshName, GetArguments, OutputToConsole, Reify, ResolveImport, SetParameters, SetReturnType, ToTargetLanguageType, AnyParadigm as AP} +import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddCompilationUnit, AddCustomFile, AddImport, AddTestCase, AddTestSuite, AddTypeLookup, Apply, Debug, FreshName, GetArguments, Reify, ResolveImport, SetParameters, SetReturnType, ToTargetLanguageType, AnyParadigm as AP} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, FileWithPath, Understands} @@ -72,11 +70,6 @@ trait AnyParadigm[A, S](val ast: AnyAST & A, val syntax: AbstractSyntax.Abstract (context, ()) } } - implicit val canOutputToConsole: Understands[MethodBodyContext, OutputToConsole[syntax.Expression]] = new Understands[MethodBodyContext, OutputToConsole[syntax.Expression]] { - def perform(context: MethodBodyContext, command: OutputToConsole[syntax.Expression]): (MethodBodyContext, Unit) = { - (context, ()) - } - } implicit val canAddImportInMethodBody: Understands[MethodBodyContext, AddImport[syntax.Import]] = new Understands[MethodBodyContext, AddImport[syntax.Import]] { def perform(context: MethodBodyContext, command: AddImport[syntax.Import]): (MethodBodyContext, Unit) = { @@ -140,7 +133,7 @@ trait AnyParadigm[A, S](val ast: AnyAST & A, val syntax: AbstractSyntax.Abstract } } - // Seem to be missing 'canAddBlockDefinitionsInTest + // Seem to be missing 'canAddBlockDefinitionsInTest' implicit val canAddTestCaseInTest: Understands[TestContext, AddTestCase[Method, Name, Expression]] = new Understands[TestContext, AddTestCase[Method, Name, Expression]] { def perform(context: TestContext, command: AddTestCase[Method, Name, Expression]): (TestContext, Unit) = { @@ -154,13 +147,14 @@ trait AnyParadigm[A, S](val ast: AnyAST & A, val syntax: AbstractSyntax.Abstract // underlying methods to exceed their maximum size. val groups = result.sliding(25,25) + var lastFresh:Name = command.name val blocks = groups.map(g => { val emptyMethod = factory.method( name = sample.getFreshName(command.name), typeLookupMap = context.methodTypeLookupMap ) - val (generatedMethod, _) = Command.runGenerator(command.code, emptyMethod) - generatedMethod.addTestExpressions(g) + lastFresh = sample.getFreshName(lastFresh) // prepare for next time + sample.addTestExpressions(g) // when emptymethod, scala generation fails to generation intermediate stmts instantiating arrays }) (context.copy(tests = context.tests ++ blocks), ()) } diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arithmetic.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arithmetic.scala index c5898945..d68c6873 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arithmetic.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arithmetic.scala @@ -1,12 +1,9 @@ -package org.combinators.ep.language.inbetween.ffi - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.Apply import org.combinators.cogen.paradigm.ffi.{Add, Div, LE, LT, Mod, Mult, Sub, Arithmetic as Arith} import org.combinators.cogen.{Command, Understands} import org.combinators.cogen.Command.Generator -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyParadigm diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArithmeticAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArithmeticAST.scala index 1264df09..c508e7ac 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArithmeticAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArithmeticAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ trait ArithmeticAST extends OperatorExpressionOpsAST { object arithmeticOps { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arrays.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arrays.scala new file mode 100644 index 00000000..8719c0a0 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Arrays.scala @@ -0,0 +1,53 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +import org.combinators.cogen.paradigm.Apply +import org.combinators.cogen.paradigm.ffi.{CreateArray, Get, Length, Set, Arrays as Arys} +import org.combinators.cogen.{Command, Understands} +import org.combinators.cogen.Command.Generator +import org.combinators.ep.language.inbetween.any.AnyParadigm + +trait Arrays[AST <: ArraysAST, B](val _base: AnyParadigm.WithAST[AST] & B) { + trait ArraysInMethods extends Arys[_base.ast.any.Method] { + val base: _base.type = _base + + import base.ast.arraysOpsFactory + import base.ast.any + + override val arrayCapabilities: ArrayCapabilities = new ArrayCapabilities { + override implicit val canCreate: Understands[any.Method, CreateArray[any.Type,any.Expression]] = + new Understands[any.Method, CreateArray[any.Type, any.Expression]] { + override def perform(context: any.Method, command: CreateArray[any.Type, any.Expression]): (any.Method, any.Expression) = { + (context, arraysOpsFactory.createArray(command.elementType, command.dimensions, command.contentSpec)) + } + } + override implicit val canGet: Understands[any.Method, Apply[Get, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[Get, any.Expression, any.Expression]] { + override def perform(context: any.Method, command: Apply[Get, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, arraysOpsFactory.getArrayOp(command.arguments(0), command.arguments.drop(1))) + } + } + override implicit val canSet: Understands[any.Method, Apply[Set, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[Set, any.Expression, any.Expression]] { + override def perform(context: any.Method, command: Apply[Set, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, arraysOpsFactory.setArrayOp(command.arguments(0), command.arguments.drop(2), command.arguments(1))) + } + } + override implicit val canLength: Understands[any.Method, Apply[Length, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[Length, any.Expression, any.Expression]] { + override def perform(context: any.Method, command: Apply[Length, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, arraysOpsFactory.lengthArrayExpression(command.arguments(0), command.arguments.drop(1))) + } + } + } + override def enable(): Generator[any.Project, Unit] = Command.skip[any.Project] + } + + val arraysInMethods: ArraysInMethods = new ArraysInMethods {} +} + +object Arrays { + type WithBase[AST <: ArraysAST, B <: AnyParadigm.WithAST[AST]] = Arrays[AST, B] {} + + def apply[AST <: ArraysAST, B <: AnyParadigm.WithAST[AST]](_base: B): WithBase[AST, B] = new Arrays[AST, B](_base) {} +} + diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArraysAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArraysAST.scala new file mode 100644 index 00000000..25ccb4e8 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ArraysAST.scala @@ -0,0 +1,154 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +import org.combinators.ep.language.inbetween.polymorphism.ParametricPolymorphismAST + +trait ArraysAST extends OperatorExpressionOpsAST with ParametricPolymorphismAST { + object arraysOps { + trait FinalTypes { + type Array <: arraysOps.Array + + type CreateArrayExpression <: arraysOps.CreateArray + type CreateArrayFromExpression <: arraysOps.CreateArrayFromExpression + type CreateArrayWithDefaultValues <: arraysOps.CreateArrayWithDefaultValues + type CreateArrayFromValues <: arraysOps.CreateArrayFromValues + + type ArrayExpression <: arraysOps.ArrayExpression + type LengthArrayExpression <: arraysOps.LengthArrayExpression + type SetArrayExpression <: arraysOps.SetArrayExpression + } + + trait Array extends any.Type { + def getSelfArrayType: arraysOpsFinalTypes.Array + } + + trait CreateArray extends any.Expression { + def getSelfCreateArrayExpression: arraysOpsFinalTypes.CreateArrayExpression + } + + trait CreateArrayFromExpression extends CreateArray { + def getSelfCreateArrayFromExpression: arraysOpsFinalTypes.CreateArrayFromExpression + def expression: any.Expression + def copy(expression: any.Expression = this.expression): CreateArrayFromExpression = + arraysOpsFactory.createArrayFromExpression(expression) + } + + trait CreateArrayWithDefaultValues extends CreateArray { + def getSelfCreateArrayWithDefaultValues: arraysOpsFinalTypes.CreateArrayWithDefaultValues + def tpe: any.Type + def dimensions: Seq[any.Expression] + def copy(tpe: any.Type = this.tpe, dimensions: Seq[any.Expression] = this.dimensions): CreateArrayWithDefaultValues = + arraysOpsFactory.createArrayWithDefaultValues(tpe, dimensions) + } + + trait CreateArrayFromValues extends CreateArray { + def getSelfCreateArrayFromValues: arraysOpsFinalTypes.CreateArrayFromValues + def values: Seq[any.Expression] + def copy(values: Seq[any.Expression] = this.values): CreateArrayFromValues = + arraysOpsFactory.createArrayFromValues(values) + } + + // expect usage is for gets and length + trait ArrayExpression extends any.Expression { + def getSelfArrayExpression: arraysOpsFinalTypes.ArrayExpression + + def base: any.Expression + def indices: Seq[any.Expression] + + def copy( + base: any.Expression = base, + indices: Seq[any.Expression] = indices + ): ArrayExpression = arraysOpsFactory.arrayExpression(base, indices) + } + + // this includes value for set + trait SetArrayExpression extends any.Expression { + def getSelfSetArrayExpression: arraysOpsFinalTypes.SetArrayExpression + def base: any.Expression + def indices: Seq[any.Expression] + def value: any.Expression + + def copy( + base: any.Expression = base, + indices: Seq[any.Expression] = indices, + value: any.Expression = value + ): SetArrayExpression = arraysOpsFactory.setArrayExpression(base, indices, value) + } + +// trait GetArrayOp extends operatorExpressions.Operator +// +// trait SetArrayOp extends operatorExpressions.Operator +// + trait LengthArrayExpression extends any.Expression { + def getSelfLengthArrayExpression: arraysOpsFinalTypes.LengthArrayExpression + def base: any.Expression + def indices: Seq[any.Expression] + + def copy( + base: any.Expression = base, + indices: Seq[any.Expression] = indices + ): LengthArrayExpression = arraysOpsFactory.lengthArrayExpression(base, indices) + } + + trait Factory { + + def array(): arraysOps.Array + + def array(elementType: any.Type): any.Type = { + polymorphismFactory.typeApplication(array(), Seq(elementType)) + } + + def createArrayFromExpression(expression: any.Expression): CreateArrayFromExpression + + def createArrayWithDefaultValues(tpe: any.Type, dimensions: Seq[any.Expression]): CreateArrayWithDefaultValues + + def createArrayFromValues(values: Seq[any.Expression]): CreateArrayFromValues + + def createArray(tpe: any.Type, dimensions: Seq[any.Expression], contentSpec: Option[(Seq[Int], Seq[any.Expression])]): any.Expression = { + contentSpec match { + case Some((dims, values)) => + val initializers = dimensions.zip(dims).reverse.tail.foldLeft[(any.Type, Seq[any.Expression])]({ + val arrayTpe = array(tpe) + val arrayExpr = values.grouped(dims.last).toSeq.map(subSeq => + arraysOpsFactory.createArrayFromValues(subSeq)) + (arrayTpe, arrayExpr) + }) { case ((arrayTpe, inits), (dimension, dim)) => + val outerArrayTpe = arraysOpsFactory.array(arrayTpe) + val outerArrayExpr = inits.grouped(dim).toSeq.map(subSeq => + arraysOpsFactory.createArrayFromValues(subSeq)) + (outerArrayTpe, outerArrayExpr) + } + + initializers._2.head + + case None => createArrayWithDefaultValues(tpe, dimensions) + } + } + + def arrayExpression(base: any.Expression, indices: Seq[any.Expression]): ArrayExpression + def setArrayExpression(base: any.Expression, indices: Seq[any.Expression], value: any.Expression): SetArrayExpression + def lengthArrayExpression(base: any.Expression, indices: Seq[any.Expression]): LengthArrayExpression + +// def getArrayOp(): GetArrayOp +// def setArrayOp(): SetArrayOp +// def lengthArrayOp(): LengthArrayOp + + def getArrayOp(ar: any.Expression, indices: Seq[any.Expression]): arraysOpsFinalTypes.ArrayExpression = + arraysOpsFactory.arrayExpression(ar, indices) + def setArrayOp(ar: any.Expression, indices: Seq[any.Expression], value: any.Expression): arraysOpsFinalTypes.SetArrayExpression = + arraysOpsFactory.setArrayExpression(ar, indices, value) + def lengthArrayOp(ar: any.Expression, indices: Seq[any.Expression]): arraysOpsFinalTypes.LengthArrayExpression = + arraysOpsFactory.lengthArrayExpression(ar, indices) + + implicit def convert(other: CreateArray): arraysOpsFinalTypes.CreateArrayExpression = other.getSelfCreateArrayExpression + implicit def convert(other: CreateArrayFromExpression): arraysOpsFinalTypes.CreateArrayFromExpression = other.getSelfCreateArrayFromExpression + implicit def convert(other: CreateArrayFromValues): arraysOpsFinalTypes.CreateArrayFromValues = other.getSelfCreateArrayFromValues + implicit def convert(other: CreateArrayWithDefaultValues): arraysOpsFinalTypes.CreateArrayWithDefaultValues = other.getSelfCreateArrayWithDefaultValues + implicit def convert(other: ArrayExpression): arraysOpsFinalTypes.ArrayExpression = other.getSelfArrayExpression + implicit def convert(other: SetArrayExpression): arraysOpsFinalTypes.SetArrayExpression = other.getSelfSetArrayExpression + implicit def convert(other: LengthArrayExpression): arraysOpsFinalTypes.LengthArrayExpression = other.getSelfLengthArrayExpression + } + } + + val arraysOpsFinalTypes: arraysOps.FinalTypes + val arraysOpsFactory: arraysOps.Factory +} diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Assertions.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Assertions.scala index 95c835be..9fa32ff7 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Assertions.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Assertions.scala @@ -1,15 +1,11 @@ -package org.combinators.ep.language.inbetween.ffi - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.Apply import org.combinators.cogen.paradigm.ffi.{Assert, Assertions as Asrts} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, Understands} -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyParadigm -// cannot find 'assertions' trait Assertions[AST <: AssertionsAST, B](val _base: AnyParadigm.WithAST[AST] & B) { trait AssertionsInMethods extends Asrts[_base.ast.any.Method] { val base: _base.type = _base diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/AssertionsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/AssertionsAST.scala index 4591fbea..80a5b16c 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/AssertionsAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/AssertionsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ trait AssertionsAST extends OperatorExpressionOpsAST { object assertionOps { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/BooleanAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/BooleanAST.scala index 661b40e4..6366b9f7 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/BooleanAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/BooleanAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ trait BooleanAST extends OperatorExpressionOpsAST { object booleanOps { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Booleans.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Booleans.scala index 74fffce2..ce0cc1b6 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Booleans.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Booleans.scala @@ -1,18 +1,12 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ -/*DI:LI:AI*/ - -import org.combinators.cogen.TypeRep import org.combinators.cogen.paradigm.Apply import org.combinators.cogen.paradigm.ffi.{And, False, Not, Or, True, Booleans as Bools} import org.combinators.cogen.Command.Generator import org.combinators.cogen.Understands -import org.combinators.cogen.paradigm.ffi.* -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyParadigm import org.combinators.cogen.Command -// cannot find 'boolean' trait Booleans[AST <: BooleanAST, B](val _base: AnyParadigm.WithAST[AST] & B) { trait BooleansInMethods extends Bools[_base.ast.any.Method] { override val base: _base.type = _base diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Console.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Console.scala new file mode 100644 index 00000000..f5f8c8b3 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Console.scala @@ -0,0 +1,32 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +import org.combinators.cogen.paradigm.Apply +import org.combinators.cogen.paradigm.ffi.{Print, Console as Cnsl} +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{Command, Understands} +import org.combinators.ep.language.inbetween.any.AnyParadigm + +trait Console[AST <: ConsoleAST, B](val _base: AnyParadigm.WithAST[AST] & B) { + trait ConsoleInMethods extends Cnsl[_base.ast.any.Method] { + val base: _base.type = _base + import base.ast.consoleOpsFactory + import base.ast.any + + val consoleCapabilities: ConsoleCapabilities = new ConsoleCapabilities { + implicit val canPrint: Understands[any.Method, Apply[Print.type, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[Print.type, any.Expression, any.Expression]] { + def perform(context: any.Method, command: Apply[Print.type, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, consoleOpsFactory.consolePrintOp(command.arguments.head)) + } + } + } + def enable(): Generator[any.Project, Unit] = Command.skip[any.Project] + } + val consoleInMethods: ConsoleInMethods = new ConsoleInMethods {} +} + +object Console { + type WithBase[AST <: ConsoleAST, B <: AnyParadigm.WithAST[AST]] = Console[AST, B] {} + + def apply[AST <: ConsoleAST, B <: AnyParadigm.WithAST[AST]](_base: B): WithBase[AST, B] = new Console[AST, B](_base) {} +} \ No newline at end of file diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ConsoleAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ConsoleAST.scala new file mode 100644 index 00000000..41ba5534 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ConsoleAST.scala @@ -0,0 +1,15 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +trait ConsoleAST extends OperatorExpressionOpsAST { + object consoleOps { + trait ConsolePrintOp extends operatorExpressions.Operator + + trait Factory { + def consolePrintOp(): ConsolePrintOp + + def consolePrintOp(exp: any.Expression): operatorExpressions.UnaryExpression = + operatorExpressionsFactory.unaryExpression(consolePrintOp(), exp) + } + } + val consoleOpsFactory: consoleOps.Factory +} diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Equals.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Equals.scala index 650552b7..485bf528 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Equals.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Equals.scala @@ -1,15 +1,11 @@ -package org.combinators.ep.language.inbetween.ffi - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, Understands} -import org.combinators.cogen.paradigm.ffi.{Equality as Eqls, *} +import org.combinators.cogen.paradigm.ffi.Equality as Eqls import org.combinators.cogen.paradigm.{Apply, ffi} -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyParadigm - trait Equals[AST <: EqualsAST, B](val _base: AnyParadigm.WithAST[AST] & B) { trait BooleansInMethods extends Eqls[_base.ast.any.Method] { override val base: _base.type = _base diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/EqualsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/EqualsAST.scala index 549b8d5c..e21bdef9 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/EqualsAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/EqualsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ trait EqualsAST extends OperatorExpressionOpsAST { object equalsOp { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Exceptions.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Exceptions.scala new file mode 100644 index 00000000..500e1a93 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Exceptions.scala @@ -0,0 +1,36 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +import org.combinators.cogen.paradigm.ffi.{Exception, Exceptions as Excptns} +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{Command, Understands} +import org.combinators.ep.language.inbetween.any.AnyParadigm + +trait Exceptions[AST <: ExceptionsAST, B](val _base: AnyParadigm.WithAST[AST] & B) { + trait ExceptionsInMethods extends Excptns[_base.ast.any.Method] { + val base: _base.type = _base + import base.ast.exceptionsOpsFactory + import base.ast.any + import base.ast + + val exceptionsCapabilities: ExceptionsCapabilities = new ExceptionsCapabilities { + + implicit val canRaise: Understands[any.Method, Exception[any.Expression, any.Statement]] = + new Understands[any.Method,Exception[any.Expression, any.Statement]] { + def perform(context: any.Method, command: Exception[any.Expression, any.Statement]): (any.Method, any.Statement) = { + val expr = exceptionsOpsFactory.raiseOp(command.exp) + + // Need to convert this EXPR into a STATEMENT + (context, ???) + } + } + } + def enable(): Generator[any.Project, Unit] = Command.skip[any.Project] + } + val exceptionsInMethods: ExceptionsInMethods = new ExceptionsInMethods {} +} + +object Exceptions { + type WithBase[AST <: ExceptionsAST, B <: AnyParadigm.WithAST[AST]] = Exceptions[AST, B] {} + + def apply[AST <: ExceptionsAST, B <: AnyParadigm.WithAST[AST]](_base: B): WithBase[AST, B] = new Exceptions[AST, B](_base) {} +} \ No newline at end of file diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ExceptionsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ExceptionsAST.scala new file mode 100644 index 00000000..cc12bc26 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ExceptionsAST.scala @@ -0,0 +1,18 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +// need to change to trait RaiseOp extends any.Statement instead. +// add final types, like with arrays/maps + +trait ExceptionsAST extends OperatorExpressionOpsAST { + object exceptionsOps { + trait RaiseOp extends operatorExpressions.Operator + + trait Factory { + def raiseOp(): RaiseOp + + def raiseOp(exp: any.Expression): operatorExpressions.UnaryExpression = + operatorExpressionsFactory.unaryExpression(raiseOp(), exp) + } + } + val exceptionsOpsFactory: exceptionsOps.Factory +} diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Lists.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Lists.scala index d30ec494..5d93cc78 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Lists.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Lists.scala @@ -1,14 +1,9 @@ -package org.combinators.ep.language.inbetween.ffi - -/*DI:LI:AI*/ - -// cannot find 'lists' +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.Apply import org.combinators.cogen.paradigm.ffi.{Append, Cons, Create, Head, Tail, Lists as Lsts} import org.combinators.cogen.{Command, Understands} import org.combinators.cogen.Command.Generator -import org.combinators.ep.language.inbetween.{any, polymorphism} import org.combinators.ep.language.inbetween.any.AnyParadigm trait Lists[AST <: ListsAST, B](val _base: AnyParadigm.WithAST[AST] & B) { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ListsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ListsAST.scala index 062c6931..8248ede1 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ListsAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/ListsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.ep.language.inbetween.polymorphism.ParametricPolymorphismAST diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Maps.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Maps.scala new file mode 100644 index 00000000..9bd57b29 --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Maps.scala @@ -0,0 +1,58 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +import org.combinators.cogen.paradigm.Apply +import org.combinators.cogen.paradigm.ffi.{ContainsKey, CreateMap, GetOrElse, Put, Maps as Mps} +import org.combinators.cogen.{Command, Understands} +import org.combinators.cogen.Command.Generator +import org.combinators.ep.language.inbetween.{any, polymorphism} +import org.combinators.ep.language.inbetween.any.AnyParadigm + +trait Maps[AST <: MapsAST, B](val _base: AnyParadigm.WithAST[AST] & B) { + // TODO: These are defined in Method context. What about constructor? What about Class context when needing to add Field? + trait MapsIn[Ctxt] extends Mps[Ctxt] { + val base: _base.type = _base + + import base.ast.mapsOpsFactory + import base.ast.any + + override val mapCapabilities: MapCapabilities = new MapCapabilities { + override implicit val canCreate: Understands[Ctxt, Apply[CreateMap[any.Type], (any.Expression,any.Expression), any.Expression]] = + new Understands[Ctxt, Apply[CreateMap[any.Type], (any.Expression,any.Expression), any.Expression]] { + override def perform(context: Ctxt, command: Apply[CreateMap[any.Type], (any.Expression, any.Expression), any.Expression]): (Ctxt, any.Expression) = { + (context, mapsOpsFactory.createMap(command.functional.keyType, command.functional.elementType, command.arguments)) + } + } + override implicit val canContainsKey: Understands[Ctxt, Apply[ContainsKey, any.Expression, any.Expression]] = + new Understands[Ctxt, Apply[ContainsKey, any.Expression, any.Expression]] { + override def perform(context: Ctxt, command: Apply[ContainsKey, any.Expression, any.Expression]): (Ctxt, any.Expression) = { + (context, mapsOpsFactory.containsKey(command.arguments(0), command.arguments(1))) + } + } + override implicit val canGet: Understands[Ctxt, Apply[GetOrElse, any.Expression, any.Expression]] = + new Understands[Ctxt, Apply[GetOrElse, any.Expression, any.Expression]] { + override def perform(context: Ctxt, command: Apply[GetOrElse, any.Expression, any.Expression]): (Ctxt, any.Expression) = { + (context, mapsOpsFactory.get(command.arguments(0), command.arguments(1), command.arguments(2))) + } + } + override implicit val canPut: Understands[Ctxt, Apply[Put[any.Type], any.Expression, any.Expression]] = + new Understands[Ctxt, Apply[Put[any.Type], any.Expression, any.Expression]] { + override def perform(context: Ctxt, command: Apply[Put[any.Type], any.Expression, any.Expression]): (Ctxt, any.Expression) = { + (context, mapsOpsFactory.put(command.arguments(0), command.functional.keyType, command.functional.valueType, command.arguments(1), command.arguments(2))) + } + } + } + override def enable(): Generator[any.Project, Unit] = Command.skip[any.Project] + } + + // TODO: These are only for methods. What about constructors? Which are based on OO concept? And so might not be part of inBetween? + + def mapsIn[Ctxt]: MapsIn[Ctxt] = new MapsIn[Ctxt] {} + val mapsInMethods:MapsIn[_base.ast.any.Method] = mapsIn[_base.ast.any.Method] +} + +object Maps { + type WithBase[AST <: MapsAST, B <: AnyParadigm.WithAST[AST]] = Maps[AST, B] {} + + def apply[AST <: MapsAST, B <: AnyParadigm.WithAST[AST]](_base: B): WithBase[AST, B] = new Maps[AST, B](_base) {} +} + diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/MapsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/MapsAST.scala new file mode 100644 index 00000000..f9c7531e --- /dev/null +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/MapsAST.scala @@ -0,0 +1,71 @@ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ + +import org.combinators.ep.language.inbetween.polymorphism.ParametricPolymorphismAST + +trait MapsAST extends OperatorExpressionOpsAST with ParametricPolymorphismAST { + object mapsOps { + trait FinalTypes { + type Map <: mapsOps.Map + type CreateMapExpression <: mapsOps.CreateMap + } + + trait Map extends any.Type { + def getSelfMapType: mapsOpsFinalTypes.Map + + def copy() : Map = mapsOpsFactory.map() + } + + trait CreateMap extends any.Expression { + def getSelfCreateMapExpression: mapsOpsFinalTypes.CreateMapExpression + + def keyType:any.Type + def elementType: any.Type + + def initialKeyValuePairs: Seq[(any.Expression,any.Expression)] + + def copy(keyType: any.Type = this.keyType, + elementType: any.Type = this.elementType, + initialKeyValuePairs: Seq[(any.Expression, any.Expression)] = this.initialKeyValuePairs): CreateMap = + mapsOpsFactory.createMap(keyType, elementType, initialKeyValuePairs) + } + + trait ContainsKeyOp extends operatorExpressions.Operator + trait GetOp extends operatorExpressions.Operator + trait PutOp extends operatorExpressions.Operator { + def keyType: any.Type + def elementType: any.Type + + def copy(keyType: any.Type = this.keyType, elementType: any.Type = this.elementType): PutOp = mapsOpsFactory.putOp(keyType = keyType, elementType = elementType) + } + + trait Factory { + def createMap(keyType: any.Type, + elementType: any.Type, + keyValuePairs: Seq[(any.Expression,any.Expression)]): CreateMap + + def map(): Map + def map(keyType: any.Type, elementType: any.Type): any.Type = { + polymorphismFactory.typeApplication(map(), Seq(keyType, elementType)) + } + + def containsKeyOp(): ContainsKeyOp + def getOp(): GetOp + def putOp(keyType:any.Type, elementType: any.Type): PutOp + + def containsKey(map: any.Expression, key: any.Expression): operatorExpressions.BinaryExpression = + operatorExpressionsFactory.binaryExpression(containsKeyOp(), map, key) + + def get(map: any.Expression, key: any.Expression, defaultValue: any.Expression): operatorExpressions.TernaryExpression = + operatorExpressionsFactory.ternaryExpression(getOp(), map, key, defaultValue) + + def put(map: any.Expression, keyType: any.Type, elementType: any.Type, key: any.Expression, value: any.Expression): operatorExpressions.TernaryExpression = + operatorExpressionsFactory.ternaryExpression(putOp(keyType, elementType), map, key, value) + + implicit def convert(other: CreateMap): mapsOpsFinalTypes.CreateMapExpression = other.getSelfCreateMapExpression + implicit def convert(other: Map): mapsOpsFinalTypes.Map = other.getSelfMapType + } + } + + val mapsOpsFinalTypes: mapsOps.FinalTypes + val mapsOpsFactory: mapsOps.Factory +} diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/OperatorExpressionOpsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/OperatorExpressionOpsAST.scala index b2a75b3e..77d0057f 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/OperatorExpressionOpsAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/OperatorExpressionOpsAST.scala @@ -1,15 +1,29 @@ -package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyAST trait OperatorExpressionOpsAST extends AnyAST { object operatorExpressions { trait FinalTypes { type Operator <: operatorExpressions.Operator + type TernaryExpression <: operatorExpressions.TernaryExpression type BinaryExpression <: operatorExpressions.BinaryExpression type UnaryExpression <: operatorExpressions.UnaryExpression } + + trait TernaryExpression extends any.Expression { + def getSelfTernaryExpression: operatorExpressionsFinalTypes.TernaryExpression + def operator: Operator + def left: any.Expression + def mid: any.Expression + def right: any.Expression + def copy( + operator: Operator = operator, + left: any.Expression = left, + mid: any.Expression = mid, + right: any.Expression = right + ): TernaryExpression = operatorExpressionsFactory.ternaryExpression(operator, left, mid, right) + } trait BinaryExpression extends any.Expression { def getSelfBinaryExpression: operatorExpressionsFinalTypes.BinaryExpression @@ -40,12 +54,15 @@ trait OperatorExpressionOpsAST extends AnyAST { } trait Factory { + def ternaryExpression(operator: Operator, left: any.Expression, middle: any.Expression, right: any.Expression): TernaryExpression def binaryExpression(operator: Operator, left: any.Expression, right: any.Expression): BinaryExpression def unaryExpression(operator: Operator, operand: any.Expression): UnaryExpression implicit def convert(other: Operator): operatorExpressionsFinalTypes.Operator = other.getSelfOperator + implicit def convert(other: TernaryExpression): operatorExpressionsFinalTypes.TernaryExpression = other.getSelfTernaryExpression implicit def convert(other: BinaryExpression): operatorExpressionsFinalTypes.BinaryExpression = other.getSelfBinaryExpression implicit def convert(other: UnaryExpression): operatorExpressionsFinalTypes.UnaryExpression = other.getSelfUnaryExpression + } } diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmetic.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmetic.scala index 85cad49e..36beb96b 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmetic.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmetic.scala @@ -1,12 +1,9 @@ -package org.combinators.ep.language.inbetween.ffi - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.Apply -import org.combinators.cogen.paradigm.ffi.{Abs, Add, Cos, Div, EulersNumber, Floor, LE, LT, Log, Mod, Mult, Pi, Pow, Sin, Sqrt, Sub, RealArithmetic as RealArith} +import org.combinators.cogen.paradigm.ffi.{Abs, Cos, EulersNumber, Floor, Log, Max, Min, Pi, Pow, Sin, Sqrt, RealArithmetic as RealArith} import org.combinators.cogen.{Command, Understands} import org.combinators.cogen.Command.Generator -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyParadigm trait RealArithmetic[AST <: RealArithmeticAST, B, T](val _base: AnyParadigm.WithAST[AST] & B) { @@ -35,6 +32,21 @@ trait RealArithmetic[AST <: RealArithmeticAST, B, T](val _base: AnyParadigm.With (context, realArithmeticOpsFactory.log(command.arguments(0), command.arguments(1))) } } + + implicit val canMax: Understands[any.Method, Apply[Max[T], any.Expression, any.Expression]] = + new Understands[any.Method, Apply[Max[T], any.Expression, any.Expression]] { + def perform(context: any.Method, command: Apply[Max[T], any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, realArithmeticOpsFactory.max(command.arguments(0), command.arguments(1))) + } + } + + implicit val canMin: Understands[any.Method, Apply[Min[T], any.Expression, any.Expression]] = + new Understands[any.Method, Apply[Min[T], any.Expression, any.Expression]] { + def perform(context: any.Method, command: Apply[Min[T], any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, realArithmeticOpsFactory.min(command.arguments(0), command.arguments(1))) + } + } + implicit val canSin: Understands[any.Method, Apply[Sin[T], any.Expression, any.Expression]] = new Understands[any.Method, Apply[Sin[T], any.Expression, any.Expression]] { def perform(context: any.Method, command: Apply[Sin[T], any.Expression, any.Expression]): (any.Method, any.Expression) = { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmeticAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmeticAST.scala index 83a72a59..793435a8 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmeticAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/RealArithmeticAST.scala @@ -1,10 +1,12 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ trait RealArithmeticAST extends OperatorExpressionOpsAST { object realArithmeticOps { trait SqrtOp extends operatorExpressions.Operator trait PowOp extends operatorExpressions.Operator trait LogOp extends operatorExpressions.Operator + trait MaxOp extends operatorExpressions.Operator + trait MinOp extends operatorExpressions.Operator trait SinOp extends operatorExpressions.Operator trait CosOp extends operatorExpressions.Operator trait AbsOp extends operatorExpressions.Operator @@ -16,6 +18,8 @@ trait RealArithmeticAST extends OperatorExpressionOpsAST { def sqrtOp(): SqrtOp def powOp(): PowOp def logOp(): LogOp + def maxOp(): MaxOp + def minOp(): MinOp def sinOp(): SinOp def cosOp(): CosOp def absOp(): AbsOp @@ -31,6 +35,11 @@ trait RealArithmeticAST extends OperatorExpressionOpsAST { def log(of: any.Expression, base: any.Expression): operatorExpressions.BinaryExpression = operatorExpressionsFactory.binaryExpression(logOp(), of, base) // FIXME: unaryExpression(logOp(), of) + + def max(left: any.Expression, right: any.Expression): operatorExpressions.BinaryExpression = + operatorExpressionsFactory.binaryExpression(maxOp(), left, right) + def min(left: any.Expression, right: any.Expression): operatorExpressions.BinaryExpression = + operatorExpressionsFactory.binaryExpression(minOp(), left, right) def sin(of: any.Expression): operatorExpressions.UnaryExpression = operatorExpressionsFactory.unaryExpression(sinOp(), of) def cos(of: any.Expression): operatorExpressions.UnaryExpression = diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/StringAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/StringAST.scala index 07be1b7f..27290a25 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/StringAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/StringAST.scala @@ -1,23 +1,31 @@ -package org.combinators.ep.language.inbetween.ffi +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ trait StringAST extends OperatorExpressionOpsAST { object stringOps { - trait ToStringOp extends operatorExpressions.Operator trait AppendStringOp extends operatorExpressions.Operator + trait GetCharAtOp extends operatorExpressions.Operator trait StringLengthOp extends operatorExpressions.Operator - + trait SubStringOp extends operatorExpressions.Operator + trait ToStringOp extends operatorExpressions.Operator trait Factory { - def toStringOp(): ToStringOp def appendStringOp(): AppendStringOp + def getCharAtOp(): GetCharAtOp def stringLengthOp(): StringLengthOp + def subStringOp(): SubStringOp + def toStringOp(): ToStringOp - def toString(exp: any.Expression): operatorExpressions.UnaryExpression = - operatorExpressionsFactory.unaryExpression(toStringOp(), exp) def appendString(left: any.Expression, right: any.Expression): operatorExpressions.BinaryExpression = operatorExpressionsFactory.binaryExpression(appendStringOp(), left, right) + + def getCharAt(base: any.Expression, idx: any.Expression): operatorExpressions.BinaryExpression = + operatorExpressionsFactory.binaryExpression(getCharAtOp(), base, idx) def stringLength(exp: any.Expression): operatorExpressions.UnaryExpression = operatorExpressionsFactory.unaryExpression(stringLengthOp(), exp) + def subString(base:any.Expression, left: any.Expression, right:any.Expression): operatorExpressions.TernaryExpression = + operatorExpressionsFactory.ternaryExpression(subStringOp(), base, left, right) + def toString(exp: any.Expression): operatorExpressions.UnaryExpression = + operatorExpressionsFactory.unaryExpression(toStringOp(), exp) } } val stringOpsFactory: stringOps.Factory diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Strings.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Strings.scala index 567b8b33..6a2235d9 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Strings.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/ffi/Strings.scala @@ -1,15 +1,11 @@ -package org.combinators.ep.language.inbetween.ffi - -/*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.ffi /*DI:LI:AI*/ import org.combinators.cogen.paradigm.Apply -import org.combinators.cogen.paradigm.ffi.{GetStringLength, StringAppend, ToString, Strings as Strs} +import org.combinators.cogen.paradigm.ffi.{GetCharAt, GetStringLength, StringAppend, SubString, ToString, Strings as Strs} import org.combinators.cogen.{Command, Understands} import org.combinators.cogen.Command.Generator -import org.combinators.ep.language.inbetween.any import org.combinators.ep.language.inbetween.any.AnyParadigm -// cannot find 'strings' trait Strings[AST <: StringAST, B](val _base: AnyParadigm.WithAST[AST] & B) { trait StringsInMethods extends Strs[_base.ast.any.Method] { override val base: _base.type = _base @@ -18,6 +14,20 @@ trait Strings[AST <: StringAST, B](val _base: AnyParadigm.WithAST[AST] & B) { import base.ast.stringOpsFactory val stringCapabilities: StringCapabilities = new StringCapabilities { + implicit val canAppend: Understands[any.Method, Apply[StringAppend, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[StringAppend, any.Expression, any.Expression]] { + def perform(context: any.Method, command: Apply[StringAppend, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, command.arguments.tail.foldLeft(command.arguments.head) { case (r, l) => stringOpsFactory.appendString(r, l) }) + } + } + + implicit val canGetCharAt: Understands[any.Method, Apply[GetCharAt, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[GetCharAt, any.Expression, any.Expression]] { + def perform(context: any.Method, command: Apply[GetCharAt, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, stringOpsFactory.getCharAt(command.arguments.head, command.arguments.tail.head)) + } + } + implicit val canGetStringLength: Understands[any.Method, Apply[GetStringLength, any.Expression, any.Expression]] = new Understands[any.Method, Apply[GetStringLength, any.Expression, any.Expression]] { def perform(context: any.Method, command: Apply[GetStringLength, any.Expression, any.Expression]): (any.Method, any.Expression) = { @@ -25,12 +35,13 @@ trait Strings[AST <: StringAST, B](val _base: AnyParadigm.WithAST[AST] & B) { } } - implicit val canAppend: Understands[any.Method, Apply[StringAppend, any.Expression, any.Expression]] = - new Understands[any.Method, Apply[StringAppend, any.Expression, any.Expression]] { - def perform(context: any.Method, command: Apply[StringAppend, any.Expression, any.Expression]): (any.Method, any.Expression) = { - (context, command.arguments.tail.foldLeft(command.arguments.head) { case (r, l) => stringOpsFactory.appendString(r, l) }) + implicit val canSubString: Understands[any.Method, Apply[SubString, any.Expression, any.Expression]] = + new Understands[any.Method, Apply[SubString, any.Expression, any.Expression]] { + def perform(context: any.Method, command: Apply[SubString, any.Expression, any.Expression]): (any.Method, any.Expression) = { + (context, stringOpsFactory.subString(command.arguments.head, command.arguments.tail.head, command.arguments.tail.tail.head)) + } } - } + implicit val canToStringInCtxt: Understands[any.Method, Apply[ToString[any.Type], any.Expression, any.Expression]] = new Understands[any.Method, Apply[ToString[any.Type], any.Expression, any.Expression]] { def perform(context: any.Method, command: Apply[ToString[any.Type], any.Expression, any.Expression]): (any.Method, any.Expression) = { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalAST.scala index 5694d186..45840f76 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.functional +package org.combinators.ep.language.inbetween.functional /*DI:LI:AI*/ import org.combinators.cogen.{FileWithPath, TypeRep} import org.combinators.cogen.Command.Generator diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalParadigm.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalParadigm.scala index 5e528494..42415be9 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalParadigm.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/FunctionalParadigm.scala @@ -2,10 +2,8 @@ package org.combinators.ep.language.inbetween.functional /*DI:LI:AI*/ import org.combinators.cogen.TypeRep import org.combinators.cogen.paradigm.{AddImport, AddMethod, AddType, AddTypeConstructor, AddTypeLookup, FindMethod, FindType, InstantiateType, ResolveImport, ToTargetLanguageType, Functional as FP} -import org.combinators.cogen.Command.Generator -import org.combinators.cogen.{Command, FileWithPath, Understands, paradigm} +import org.combinators.cogen.{Command, Understands} import org.combinators.ep.language.inbetween.any.AnyParadigm -import org.combinators.ep.language.inbetween.any trait FunctionalParadigm[AST <: FunctionalAST, B](val base: AnyParadigm.WithAST[AST] & B) extends FP { import base.ast.any diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/Functional.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/Functional.scala index f0ffd0df..6470ad21 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/Functional.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/Functional.scala @@ -1,11 +1,9 @@ -package org.combinators.ep.language.inbetween.functional.control +package org.combinators.ep.language.inbetween.functional.control /*DI:LI:AI*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.paradigm.control.* -import org.combinators.cogen.paradigm.control.{DeclareFunVariable as DFV, Functional as Fun} import org.combinators.cogen.paradigm.{Apply, IfThenElse, Reify, control} -import org.combinators.cogen.{Command, Understands, paradigm} -import org.combinators.ep.language.inbetween.any +import org.combinators.cogen.{Command, Understands} import org.combinators.ep.language.inbetween.any.AnyParadigm trait Functional[AST <: FunctionalControlAST, B](val _base: AnyParadigm.WithAST[AST] & B) { @@ -44,7 +42,7 @@ trait Functional[AST <: FunctionalControlAST, B](val _base: AnyParadigm.WithAST[ (resContext, functionalControlFactory.declareFunVariable(command.name, command.tpe, isRecursive = true, initExp, inExp)) } } - + implicit val canIfThenElse: Understands[any.Method, IfThenElse[any.Expression, Generator[any.Method, any.Expression], Generator[any.Method, any.Expression], any.Expression]] = new Understands[any.Method, IfThenElse[any.Expression, Generator[any.Method, any.Expression], Generator[any.Method, any.Expression], any.Expression]] { override def perform(context: any.Method, command: IfThenElse[any.Expression, Generator[any.Method, any.Expression], Generator[any.Method, any.Expression], any.Expression]): (any.Method, any.Expression) = { diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/FunctionalControlAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/FunctionalControlAST.scala index e4853c59..c73d40b0 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/FunctionalControlAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/functional/control/FunctionalControlAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.functional.control +package org.combinators.ep.language.inbetween.functional.control /*DI:LI:AI*/ import org.combinators.cogen.TypeRep import org.combinators.ep.language.inbetween.any.AnyAST diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/Imperative.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/Imperative.scala index 9e7e493f..a05f6b40 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/Imperative.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/Imperative.scala @@ -1,15 +1,14 @@ package org.combinators.ep.language.inbetween.imperative /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{IfThenElse, control} -import org.combinators.cogen.paradigm.control.{AssignVariable, DeclareVariable, LiftExpression, Return, While} +import org.combinators.cogen.paradigm.control.{AssignVariable, DeclareVariable, LiftExpression, While} import org.combinators.cogen.Command.Generator -import org.combinators.cogen.{Command, FileWithPath, Understands, paradigm} -import org.combinators.cogen.paradigm.control.{Return, DeclareVariable as DV, Imperative as Imp} +import org.combinators.cogen.{Command, Understands} +import org.combinators.cogen.paradigm.control.Return import org.combinators.ep.language.inbetween.any.AnyParadigm - // Requires "recursive solution" to the EP, where Ctxt has a producer method and so this needs an EP solution, while -// talking about something which doesn't need to have one.. +// talking about something which doesn't need to have one. trait Imperative[AST <: ImperativeAST, B](val _base: AnyParadigm.WithAST[AST] & B) { trait ImperativeInMethods extends control.Imperative[_base.ast.any.Method] { override val base: _base.type = _base @@ -44,6 +43,7 @@ trait Imperative[AST <: ImperativeAST, B](val _base: AnyParadigm.WithAST[AST] & (context, liftStmt) } } + implicit val canIfThenElse: Understands[Ctxt, IfThenElse[any.Expression, Generator[Ctxt, Unit], Option[Generator[Ctxt, Unit]], any.Statement]] = new Understands[Ctxt, IfThenElse[any.Expression, Generator[Ctxt, Unit], Option[Generator[Ctxt, Unit]], any.Statement]] { /** Returns the updated context and the result of the command. */ diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/ImperativeAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/ImperativeAST.scala index e9a45434..49021b50 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/ImperativeAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/imperative/ImperativeAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.imperative +package org.combinators.ep.language.inbetween.imperative /*DI:LI:AI*/ import org.combinators.ep.language.inbetween.any.AnyAST @@ -7,6 +7,7 @@ trait ImperativeAST extends AnyAST { trait FinalTypes { type DeclareVariable <: imperative.DeclareVariable type AssignVariable <: imperative.AssignVariable + type Tertiary <: imperative.Tertiary type IfThenElse <: imperative.IfThenElse type While <: imperative.While type VariableReferenceExpression <: imperative.VariableReferenceExpression @@ -45,6 +46,20 @@ trait ImperativeAST extends AnyAST { def copy(expression: any.Expression = expression): LiftExpression = imperativeFactory.liftExpression(expression) } + trait Tertiary extends any.Expression { + def getSelfTertiary: imperativeFinalTypes.Tertiary + def condition: any.Expression + def trueExpression: any.Expression + def falseExpression: any.Expression + + def copy( + condition: any.Expression = condition, + trueExpression: any.Expression = trueExpression, + falseExpression: any.Expression = falseExpression + ): Tertiary = + imperativeFactory.tertiary(condition, trueExpression, falseExpression) + } + trait IfThenElse extends any.Statement { def getSelfIfThenElse: imperativeFinalTypes.IfThenElse @@ -86,6 +101,12 @@ trait ImperativeAST extends AnyAST { def assignVariable(variable: any.Expression, expression: any.Expression): AssignVariable def liftExpression(expression: any.Expression): LiftExpression + def tertiary( + condition: any.Expression, + trueExpression: any.Expression, + falseExpression: any.Expression + ): Tertiary + def ifThenElse( condition: any.Expression, ifBranch: Seq[any.Statement], diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOAST.scala index c87b6299..ee1f37e3 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.oo +package org.combinators.ep.language.inbetween.oo /*DI:LI:AI*/ import org.combinators.cogen.{FileWithPath, TypeRep} import org.combinators.cogen.Command.Generator diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOParadigm.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOParadigm.scala index 5db63150..5d05644e 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOParadigm.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/oo/OOParadigm.scala @@ -49,11 +49,6 @@ trait OOParadigm[AST <: OOAST, B](val base: AnyParadigm.WithAST[AST] & B) extend (context.copy(implemented = context.implemented :+ command.interface), ()) } } - implicit val canRemoveMethodFromClass: Understands[Class, RemoveMethod[Type, Name]] = new Understands[Class, RemoveMethod[Type, Name]] { - override def perform(context: Class, command: RemoveMethod[Type, Name]): (Class, Unit) = { - ??? // TODO: Remove me - } - } implicit val canAddFieldInClass: Understands[Class, AddField[Name, Type, Expression]] = new Understands[Class, AddField[Name, Type, Expression]] { def perform(context: Class, command: AddField[Name, Type, Expression]): (Class, Unit) = { (context.copy(fields = context.fields :+ ooFactory.field(command.name, command.tpe, command.initializer)), ()) diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphism.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphism.scala index f6f4ade3..6e41817c 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphism.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphism.scala @@ -1,13 +1,8 @@ -package org.combinators.ep.language.inbetween.polymorphism - -/*DI:LI:AI*/ - +package org.combinators.ep.language.inbetween.polymorphism /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{AddTypeParameter, Apply, GetTypeArguments, ParametricPolymorphism as PP} import org.combinators.cogen.{Command, Understands} import org.combinators.ep.language.inbetween.any.AnyParadigm -import org.combinators.ep.language.inbetween.any - trait ParametricPolymorphism[AST <: ParametricPolymorphismAST, B](val base: AnyParadigm.WithAST[AST] & B) extends PP { import base.ast.factory diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismAST.scala index 421ffb55..ff150a10 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.polymorphism +package org.combinators.ep.language.inbetween.polymorphism /*DI:LI:AI*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.TypeRep diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismInADTContexts.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismInADTContexts.scala index 19dc26c3..6e16bcbb 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismInADTContexts.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/ParametricPolymorphismInADTContexts.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.polymorphism +package org.combinators.ep.language.inbetween.polymorphism /*DI:LI:AI*/ import org.combinators.cogen.paradigm.{Apply, ParametricPolymorphismInADTContexts as PPADT} import org.combinators.cogen.Understands diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/Generics.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/Generics.scala index e5dfea95..9ababcd1 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/Generics.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/Generics.scala @@ -1,8 +1,7 @@ -package org.combinators.ep.language.inbetween.polymorphism.generics /*DI:LI:AI*/ +package org.combinators.ep.language.inbetween.polymorphism.generics /*DI:LI:AI*/ -import org.combinators.cogen.paradigm.{AddLowerBound, AddTypeParameter, AddUpperBound, Apply, GetCurrentTypeParameter, GetTypeArguments, AnyParadigm as AP, Generics as GS, ObjectOriented as OO, ParametricPolymorphism as PP} +import org.combinators.cogen.paradigm.{AddLowerBound, AddTypeParameter, AddUpperBound, Apply, GetCurrentTypeParameter, GetTypeArguments, Generics as GS} import org.combinators.cogen.{Command, Understands} -import org.combinators.cogen.paradigm.ParametricPolymorphism.WithBase import org.combinators.ep.language.inbetween.any.AnyParadigm import org.combinators.ep.language.inbetween.oo.OOParadigm import org.combinators.ep.language.inbetween.polymorphism.ParametricPolymorphism diff --git a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/GenericsAST.scala b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/GenericsAST.scala index 30aca379..1bee5173 100644 --- a/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/GenericsAST.scala +++ b/language/inbetween/src/main/scala/org/combinators/ep/language/inbetween/polymorphism/generics/GenericsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.inbetween.polymorphism.generics +package org.combinators.ep.language.inbetween.polymorphism.generics /*DI:LI:AI*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.TypeRep diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/CodeGenerator.scala b/language/java/src/main/scala/org/combinators/ep/language/java/CodeGenerator.scala index 56754f77..b63bb66c 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/CodeGenerator.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/CodeGenerator.scala @@ -3,7 +3,7 @@ package org.combinators.ep.language.java /*DI:LD:AI*/ import cats.{Apply => _} import com.github.javaparser.ast.PackageDeclaration import com.github.javaparser.ast.`type`.PrimitiveType -import com.github.javaparser.ast.expr.{DoubleLiteralExpr, IntegerLiteralExpr, TypeExpr} +import com.github.javaparser.ast.expr.{DoubleLiteralExpr, IntegerLiteralExpr} import org.combinators.cogen.TypeRep import org.combinators.cogen.Command import org.combinators.ep.language.java.paradigm._ @@ -130,6 +130,28 @@ class CodeGenerator(config: Config) { cc => ooParadigm.constructorCapabilities.canAddImportInConstructor )(generics) + val mapsInMethod = + Maps[MethodBodyCtxt, paradigm.type, Generics]( + paradigm, + paradigm.methodBodyCapabilities.canAddImportInMethodBody, + parametricPolymorphism.methodBodyCapabilities.canApplyTypeInMethod, + paradigm.methodBodyCapabilities.canGetFreshNameInMethodBody, + imperativeInMethod.imperativeCapabilities.canDeclareVariable, + imperativeInMethod.imperativeCapabilities.canLiftExpression, + paradigm.methodBodyCapabilities.canAddBlockDefinitionsInMethodBody + )(generics) + + val mapsInConstructor = + Maps[CtorCtxt, paradigm.type, Generics]( + paradigm, + ooParadigm.constructorCapabilities.canAddImportInConstructor, + generics.constructorCapabilities.canApplyTypeInConstructor, + ooParadigm.constructorCapabilities.canGetFreshNameInConstructor, + imperativeInConstructor.imperativeCapabilities.canDeclareVariable, + imperativeInConstructor.imperativeCapabilities.canLiftExpression, + ooParadigm.constructorCapabilities.canAddBlockDefinitionsInConstructor + )(generics) + val assertionsInMethod = new Assertions[paradigm.type](paradigm)(ooParadigm) val exceptionsInMethod = new Exceptions[paradigm.type](paradigm) } diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/FreshNameCleanup.scala b/language/java/src/main/scala/org/combinators/ep/language/java/FreshNameCleanup.scala index a478ae04..a6e10316 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/FreshNameCleanup.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/FreshNameCleanup.scala @@ -1,10 +1,8 @@ -package org.combinators.ep.language.java - -/*DI:LD:AI*/ +package org.combinators.ep.language.java /*DI:LD:AI*/ import com.github.javaparser.ast.body.{ClassOrInterfaceDeclaration, ConstructorDeclaration, MethodDeclaration} -import com.github.javaparser.ast.{CompilationUnit, ImportDeclaration, Node} -import com.github.javaparser.ast.expr.{CastExpr, LambdaExpr, Name, SimpleName} +import com.github.javaparser.ast.CompilationUnit +import com.github.javaparser.ast.expr.{LambdaExpr, Name, SimpleName} import com.github.javaparser.ast.stmt.{BlockStmt, CatchClause, ForEachStmt, ForStmt, SwitchEntry, SwitchStmt} import com.github.javaparser.ast.visitor.Visitable import org.combinators.cogen.FreshNameProvider diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/AnyParadigm.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/AnyParadigm.scala index 15c01c28..f8d8ced5 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/AnyParadigm.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/AnyParadigm.scala @@ -5,12 +5,12 @@ import java.util.UUID import com.github.javaparser.ast.{ImportDeclaration, Modifier, Node, NodeList} import com.github.javaparser.ast.`type`.VoidType import com.github.javaparser.ast.body.{ClassOrInterfaceDeclaration, MethodDeclaration} -import com.github.javaparser.ast.expr.{MethodCallExpr, NameExpr, NullLiteralExpr, Name as JName} +import com.github.javaparser.ast.expr.{MethodCallExpr, NameExpr, NullLiteralExpr} import com.github.javaparser.ast.nodeTypes.{NodeWithScope, NodeWithSimpleName} import com.github.javaparser.ast.stmt.{BlockStmt, ExpressionStmt} import org.combinators.cogen.InstanceRep import org.combinators.cogen.TypeRep -import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddCompilationUnit, AddCustomFile, AddImplementedTestCase, AddImport, AddTestCase, AddTestSuite, AddTypeLookup, Apply, Debug, FreshName, GetArguments, OutputToConsole, Reify, ResolveImport, SetParameters, SetReturnType, ToTargetLanguageType, AnyParadigm as AP, ObjectOriented as _} +import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddCompilationUnit, AddCustomFile, AddImplementedTestCase, AddImport, AddTestCase, AddTestSuite, AddTypeLookup, Apply, Debug, FreshName, GetArguments, Reify, ResolveImport, SetParameters, SetReturnType, ToTargetLanguageType, AnyParadigm as AP, ObjectOriented as _} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, FileWithPath, Understands} import org.combinators.ep.language.java.Syntax.MangledName @@ -18,8 +18,7 @@ import org.combinators.ep.language.java.{CodeGenerator, CompilationUnitCtxt, Con import org.combinators.templating.persistable.{BundledResource, JavaPersistable} import scala.util.Try -import scala.jdk.CollectionConverters.* - +import scala.jdk.CollectionConverters._ trait AnyParadigm extends AP { lazy val config: Config @@ -40,8 +39,8 @@ trait AnyParadigm extends AP { context: ProjectCtxt, command: Debug ): (ProjectCtxt, Unit) = { - val units = context.units.toSeq.mkString(", ") - System.err.println (command.tag + ": " + units) + + context.units.foreach (u => System.err.println (command.tag + ": " + u)) (context,()) } } @@ -194,16 +193,6 @@ trait AnyParadigm extends AP { } } - implicit val canOutputToConsole: Understands[MethodBodyCtxt, OutputToConsole[Expression]] = - new Understands[MethodBodyCtxt, OutputToConsole[Expression]] { - def perform( - context: MethodBodyCtxt, - command: OutputToConsole[Expression] - ): (MethodBodyCtxt, Unit) = { - (context.copy(), ()) - } - } - implicit val canAddImportInMethodBody: Understands[MethodBodyCtxt, AddImport[ImportDeclaration]] = new Understands[MethodBodyCtxt, AddImport[ImportDeclaration]] { def perform( @@ -240,7 +229,7 @@ trait AnyParadigm extends AP { context: MethodBodyCtxt, command: SetReturnType[Type] ): (MethodBodyCtxt, Unit) = { - val updatedMethod = { + val updatedMethod = { val oldMethod = context.method val tpe = command.tpe val newMethod = oldMethod.clone() @@ -299,7 +288,7 @@ trait AnyParadigm extends AP { val stripped = AnyParadigm.stripGenerics(command.forElem) Try { (context, context.resolver.importResolution(stripped)) } getOrElse { if (stripped.isClassOrInterfaceType) { - val importName: JName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType()) + val importName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType()) val newImport = new ImportDeclaration( importName, @@ -388,7 +377,7 @@ trait AnyParadigm extends AP { val stripped = AnyParadigm.stripGenerics(command.forElem) Try { (context, context.resolver.importResolution(stripped)) } getOrElse { if (stripped.isClassOrInterfaceType) { - val importName: JName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType()) + val importName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType()) val newImport = new ImportDeclaration( importName, diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Generics.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Generics.scala index cbf78f29..7b69575f 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Generics.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Generics.scala @@ -148,6 +148,7 @@ object Generics { override val base: b.type)( override val ooParadigm: oo.type = oo, override val ppolyParadigm: ppol.type = ppol) extends Generics[b.type] - return G(b)(oo, ppol) + + G(b)(oo, ppol) } } \ No newline at end of file diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Imperative.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Imperative.scala index c291b11b..6083127f 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Imperative.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Imperative.scala @@ -85,6 +85,7 @@ trait Imperative[Ctxt, AP <: AnyParadigm] extends Imp[Ctxt] { (manip.copyWithBlock(afterElseCtxt, manip.getBlock(context)), iteStmt.clone()) } } + implicit val canWhile: Understands[Ctxt, While[Ctxt, Expression, Statement]] = new Understands[Ctxt, While[Ctxt, Expression, Statement]] { def perform(context: Ctxt, command: While[Ctxt, Expression, Statement]): (Ctxt, Statement) = { diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Lambdas.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Lambdas.scala index 6c8300cd..604dd24b 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Lambdas.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Lambdas.scala @@ -2,29 +2,36 @@ package org.combinators.ep.language.java.paradigm /*DI:LD:AI*/ import org.combinators.cogen.paradigm.control.Lambdas as Lams import org.combinators.cogen.{Command, Understands} +import org.combinators.cogen.paradigm.control.Lambda trait Lambdas[Ctxt, AP <: AnyParadigm] extends Lams[Ctxt] { val base: AP + val imperative: Imperative[Ctxt, AP] import base.syntax._ -// object lambdaCapabilities extends LambdaCapabilities { -// implicit val canLambda: Understands[Ctxt, Lambda[Name, Type, Ctxt, Expression]] = -// new Understands[Ctxt, Lambda[Name, Type, Ctxt, Expression]] { -// def perform(context: Ctxt, command: Lambda[Name, Type, Ctxt, Expression]): (Ctxt, Statement) = { -// val params = command.variables -// val lambdaExpr = new com.github.javaparser.ast.expr.LambdaExpr() -// -// params.foreach { case (paramName, paramTpe) => -// lambdaExpr.addParameter(paramTpe.clone(), paramName.mangled) -// } -// val paramMap = params.map{ case(name, tpe) => (name, new com.github.javaparser.ast.expr.NameExpr(name.toAST))}.toMap -// val (lambdaCtxt, _) = Command.runGenerator(command.body(paramMap), manip.nextBlockContext(context)) -// -// lambdaExpr.setBody(command.body) -// whileStmt.setBody(manip.getBlock(whileCtxt)) -// (manip.copyWithBlock(whileCtxt, manip.getBlock(context)), lambdExpr) -// } -// } -// } + object lambdaCapabilities extends LambdaCapabilities { + implicit val canLambda: Understands[Ctxt, Lambda[Name, Type, Ctxt, Expression]] = + new Understands[Ctxt, Lambda[Name, Type, Ctxt, Expression]] { + def perform(context: Ctxt, command: Lambda[Name, Type, Ctxt, Expression]): (Ctxt, Expression) = { + import imperative.imperativeCapabilities.returnStmt + val params = command.variables + + val lambdaExpr = new com.github.javaparser.ast.expr.LambdaExpr() + params.foreach { case (paramName, paramTpe) => + lambdaExpr.addParameter(paramTpe.clone(), paramName.mangled) + } + val paramMap = params.map{ case(paramName, tpe) => (paramName, new com.github.javaparser.ast.expr.NameExpr(paramName.mangled))}.toMap + val lambdaGen = for { + resultExp <- command.body(paramMap) + resultStmt <- returnStmt(resultExp) + } yield resultStmt + val (lambdaCtxt, lambdaResult) = Command.runGenerator(lambdaGen, imperative.manip.nextBlockContext(context)) + val lambdaStmt = imperative.manip.getBlock(lambdaCtxt).addStatement(lambdaResult) + lambdaExpr.setBody(lambdaStmt) + + (imperative.manip.copyWithBlock(lambdaCtxt, imperative.manip.getBlock(context)), lambdaExpr) + } + } + } } \ No newline at end of file diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ObjectOriented.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ObjectOriented.scala index 263f617e..f35ab0fc 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ObjectOriented.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ObjectOriented.scala @@ -4,18 +4,18 @@ import java.util.UUID import com.github.javaparser.ast.{ImportDeclaration, Modifier, NodeList} import com.github.javaparser.ast.`type`.ClassOrInterfaceType import com.github.javaparser.ast.body.{ClassOrInterfaceDeclaration, ConstructorDeclaration, MethodDeclaration} -import com.github.javaparser.ast.expr.{AssignExpr, CastExpr, EnclosedExpr, Expression => JExpression, FieldAccessExpr, InstanceOfExpr, MethodCallExpr, NameExpr, ObjectCreationExpr, ThisExpr, TypeExpr, Name as JName} +import com.github.javaparser.ast.expr.{AssignExpr, CastExpr, EnclosedExpr, FieldAccessExpr, InstanceOfExpr, MethodCallExpr, NameExpr, ObjectCreationExpr, ThisExpr, TypeExpr, Expression as JExpression, Name as JName} import com.github.javaparser.ast.stmt.{BlockStmt, ExplicitConstructorInvocationStmt, ExpressionStmt, ReturnStmt} import org.combinators.cogen.InstanceRep import org.combinators.cogen.TypeRep -import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddClass, AddConstructor, AddField, AddImplemented, AddImport, AddMethod, AddParent, AddTypeLookup, Apply, CastObject, Debug, FindClass, FreshName, GetArguments, GetConstructor, GetField, GetMember, InitializeField, InitializeParent, InstanceOfType, InstantiateObject, Reify, RemoveMethod, ResolveImport, SelfReference, SetAbstract, SetInterface, SetOverride, SetParameters, SetStatic, SuperReference, ToTargetLanguageType, ObjectOriented as OO} +import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddClass, AddConstructor, AddField, AddImplemented, AddImport, AddMethod, AddParent, AddTypeLookup, Apply, CastObject, Debug, FindClass, FreshName, GetArguments, GetConstructor, GetField, GetMember, InitializeField, InitializeParent, InstanceOfType, InstantiateObject, Reify, ResolveImport, SelfReference, SetAbstract, SetInterface, SetOverride, SetParameters, SetStatic, SuperReference, ToTargetLanguageType, ObjectOriented as OO} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, Understands} import org.combinators.ep.language.java.Syntax.MangledName import org.combinators.ep.language.java.{ClassCtxt, ContextSpecificResolver, CtorCtxt, JavaNameProvider, MethodBodyCtxt, TestCtxt} import scala.util.Try -import scala.jdk.CollectionConverters._ +import scala.jdk.CollectionConverters.* trait ObjectOriented[AP <: AnyParadigm] extends OO { val base: AP @@ -148,21 +148,7 @@ trait ObjectOriented[AP <: AnyParadigm] extends OO { (context.copy(cls = resultCls), ()) } } - implicit val canRemoveMethodFromClass: Understands[ClassContext, RemoveMethod[Type, Name]] = - new Understands[ClassContext, RemoveMethod[Type, Name]] { - def perform( - context: ClassContext, - command: RemoveMethod[Type, Name] - ): (ClassContext, Unit) = { - val resultCls = context.cls.clone() - - // TODO: DO SOMETHING HERE (HEINEMAN) - val method = resultCls.getMethodsByName(command.name.mangled) - resultCls.remove(method.get(0)) - - (context.copy(cls = resultCls), ()) - } - } + implicit val canAddFieldInClass: Understands[ClassContext, AddField[Name, Type, Expression]] = new Understands[ClassContext, AddField[Name, Type, Expression]] { def perform( @@ -609,7 +595,7 @@ trait ObjectOriented[AP <: AnyParadigm] extends OO { (context.copy(resolver = newCtxt.resolver, extraImports = newCtxt.extraImports), result) } else { (context, result) - } + } } } diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arithmetic.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arithmetic.scala index 63769ffb..6718f43e 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arithmetic.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arithmetic.scala @@ -39,7 +39,7 @@ class Arithmetic[Ctxt, T, AP <: AnyParadigm]( infixExprOp(BinaryExpr.Operator.LESS_EQUALS) } def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arrays.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arrays.scala index b9adf1a0..c589fc13 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arrays.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arrays.scala @@ -1,40 +1,77 @@ package org.combinators.ep.language.java.paradigm.ffi /*DI:LD:AI*/ import com.github.javaparser.ast.`type`.ArrayType -import com.github.javaparser.ast.expr.{ArrayAccessExpr, ArrayCreationExpr, ArrayInitializerExpr, AssignExpr, FieldAccessExpr, IntegerLiteralExpr, MethodCallExpr, NameExpr, SimpleName} +import com.github.javaparser.ast.expr.{ArrayAccessExpr, ArrayCreationExpr, ArrayInitializerExpr, AssignExpr, FieldAccessExpr} import com.github.javaparser.ast.{ArrayCreationLevel, NodeList} -import org.combinators.cogen.InstanceRep -import org.combinators.cogen.TypeRep -import org.combinators.cogen.paradigm.{Apply, ffi} +import org.combinators.cogen.{Command, InstanceRep, TypeRep, Understands} +import org.combinators.cogen.paradigm.Apply import org.combinators.cogen.Command.Generator -import org.combinators.cogen.paradigm.AnyParadigm.syntax._ -import org.combinators.cogen.paradigm.ffi.{CreateArray, Get, Length, Arrays as Arrs} -import org.combinators.cogen.Understands +import org.combinators.cogen.paradigm.AnyParadigm.syntax.* +import org.combinators.cogen.paradigm.ffi.{CreateArray, Get, Length, Set, Arrays as Arrs} import org.combinators.ep.language.java.CodeGenerator.Enable -import org.combinators.ep.language.java.Syntax.default._ +import org.combinators.ep.language.java.Syntax.default.* import org.combinators.ep.language.java.paradigm.AnyParadigm import org.combinators.ep.language.java.{ContextSpecificResolver, ProjectCtxt} class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] { case object ArraysEnabled - def arrayCreation[Ctxt](): Understands[Ctxt, Apply[CreateArray[Type], Expression, Expression]] = - new Understands[Ctxt, Apply[CreateArray[Type], Expression, Expression]] { + def arrayCreation[Ctxt](): Understands[Ctxt, CreateArray[Type,Expression]] = + new Understands[Ctxt, CreateArray[Type,Expression]] { def perform( context: Ctxt, - command: Apply[CreateArray[Type], Expression, Expression] - ): (Ctxt, Expression) = - (context, - new ArrayCreationExpr(command.functional.elementType, - new NodeList(new ArrayCreationLevel(1)), - new ArrayInitializerExpr(new NodeList(command.arguments*))) - ) - } + command: CreateArray[Type,Expression] + ): (Ctxt, Expression) = { + + if (command.dimensions.length == 1) { + val levels = command.dimensions.map(level => if (command.contentSpec.isDefined) { new ArrayCreationLevel() } else { new ArrayCreationLevel(level) }) // inserting actual value causes problems since cannot have int[len1][len2] with initial values. + + val result = new ArrayCreationExpr(command.elementType) + result.setLevels(new NodeList(levels *)) + + command.contentSpec match { + + case Some((dims, content)) => + val initializer = command.contentSpec.map(elt => new ArrayInitializerExpr(new NodeList(elt._2*))).getOrElse(new ArrayInitializerExpr()) + result.setInitializer(initializer) + + case None => + result.setInitializer(null) + } + + (context, result) + } else { + val levels = command.dimensions.map(level => if (command.contentSpec.isDefined) { new ArrayCreationLevel() } else { new ArrayCreationLevel(level) }) // inserting actual value causes problems since cannot have int[len1][len2] with initial values. + + val result = new ArrayCreationExpr(command.elementType) + result.setLevels(new NodeList(levels *)) + + command.contentSpec match { + + case Some((dims, content)) => + val initializers = dims.reverse.tail.foldLeft[Seq[ArrayInitializerExpr]]( + content.grouped(dims.last).toSeq.map(subSeq => new ArrayInitializerExpr(new NodeList(subSeq *))) + ) { case (inits, dim) => inits.grouped(dim).toSeq.map(subSeq => new ArrayInitializerExpr(new NodeList(subSeq *))) } + result.setInitializer(initializers.head) + + case None => + result.setInitializer(null) + } + + // When creating array with initial values, cannot pass in lengths. Cannot do the following for example + // new int[2][3] { { 4, 5, 1 }, { 1, 2, 3 } } + // + // new int[expr1][expr2]; + (context, result) // new ArrayInitializerExpr(new NodeList(command.arguments: _ *))) + } + } + } + val arrayCapabilities: ArrayCapabilities = new ArrayCapabilities { - implicit val canCreate: Understands[Ctxt, Apply[CreateArray[Type], Expression, Expression]] = arrayCreation() + implicit val canCreate: Understands[Ctxt, CreateArray[Type,Expression]] = arrayCreation() implicit val canGet: Understands[Ctxt, Apply[Get, Expression, Expression]] = new Understands[Ctxt, Apply[Get, Expression, Expression]] { @@ -42,17 +79,22 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] { context: Ctxt, command: Apply[Get, Expression, Expression] ): (Ctxt, Expression) = { - (context, new ArrayAccessExpr(command.arguments(0), command.arguments(1))) + + val indices = command.arguments.tail.foldLeft(command.arguments.head) { case (acc, level) => new ArrayAccessExpr(acc, level) } + + (context, indices) } } - implicit val canSet: Understands[Ctxt, Apply[ffi.Set, Expression, Expression]] = - new Understands[Ctxt, Apply[ffi.Set, Expression, Expression]] { + implicit val canSet: Understands[Ctxt, Apply[Set, Expression, Expression]] = + new Understands[Ctxt, Apply[Set, Expression, Expression]] { override def perform( context: Ctxt, - command: Apply[ffi.Set, Expression, Expression] + command: Apply[Set, Expression, Expression] ): (Ctxt, Expression) = { - (context, new AssignExpr(new ArrayAccessExpr(command.arguments(0), command.arguments(1)), command.arguments(2), AssignExpr.Operator.ASSIGN)) + val indices = command.arguments.init.tail.foldLeft(command.arguments.head) { case (acc, level) => new ArrayAccessExpr(acc, level) } + + (context, new AssignExpr(indices, command.arguments.last, AssignExpr.Operator.ASSIGN)) } } @@ -62,13 +104,15 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] { context: Ctxt, command: Apply[Length, Expression, Expression] ): (Ctxt, Expression) = { - (context, new FieldAccessExpr(command.arguments(0), "length")) + val indices = command.arguments.tail.foldLeft(command.arguments.head) { case (acc, level) => new ArrayAccessExpr(acc, level) } + + (context, new FieldAccessExpr(indices, "length")) } } } def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type @@ -80,9 +124,10 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] { toResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type], projectResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type] ): ContextSpecificResolver => TypeRep => Generator[Ctxt, Type] = k => { - case TypeRep.Array(elemRep) => + case TypeRep.Array(elemTypeRep) => + for { - elemType <- projectResolution(k)(elemRep) + elemType <- projectResolution(k)(elemTypeRep) } yield new ArrayType(elemType) case other => toResolution(k)(other) } @@ -91,17 +136,77 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] { reify: ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression], projectResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type], projectReification: ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression], - canCreateArray: Understands[Ctxt, Apply[CreateArray[Type], Expression, Expression]] + canCreateArray: Understands[Ctxt, CreateArray[Type,Expression]] ): ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression] = k => rep => rep.tpe match { - case TypeRep.Array(elemTypeRep) => + case TypeRep.Array(elemTypeRep) => { + + + // helper function to get flattened elements + def elements(elemTypeRep:TypeRep)(elem:elemTypeRep.HostType) : Generator[Ctxt, Seq[Expression]] = { + elemTypeRep match { + case TypeRep.Array(innerElemTypeRep) => { + val seq_gen = elem.asInstanceOf[Array[innerElemTypeRep.HostType]].map(innerElem => elements(innerElemTypeRep)(innerElem)) + for { + flattened <- seq_gen.foldLeft(Command.lift[Ctxt,Seq[Expression]](Seq.empty[Expression])){ case (acc, next_gen) => + for { + acc_result <- acc + next_result <- next_gen + } yield acc_result ++ next_result + } + } yield flattened + } + + // recursively translates innermost elements + case _ => for { + elems <- forEach(elem.asInstanceOf[Seq[elemTypeRep.HostType]]) { el => + reify(k)(InstanceRep(elemTypeRep)(el)) + } + } yield elems + } + } + + // helper function to get type of innermost element -- assume homogenous array + def elementType(elemTypeRep:TypeRep)(elem:elemTypeRep.HostType) : Generator[Ctxt, Type] = { + elemTypeRep match { + case TypeRep.Array(innerElemTypeRep) => + elementType(innerElemTypeRep)(elem.asInstanceOf[Array[innerElemTypeRep.HostType]].head) + + // recursively find type of innermost element + case _ => for { + elemType <- projectResolution(k)(elemTypeRep) + } yield elemType + } + } + + // helper function to get flattened elements + def dimensions(elemTypeRep:TypeRep)(elem:elemTypeRep.HostType) : Seq[Int] = { + elemTypeRep match { + case TypeRep.Array(innerElemTypeRep) => { + val outer = elem.asInstanceOf[Seq[elemTypeRep.HostType]].length + + // inner arrays must be uniform length + val inner = dimensions(innerElemTypeRep)(elem.asInstanceOf[Array[innerElemTypeRep.HostType]].head) + outer +: inner + } + + // recursively translates innermost elements + case _ => Seq(elem.asInstanceOf[Seq[elemTypeRep.HostType]].length) + + } + } + + for { - elems <- forEach(rep.inst.asInstanceOf[Seq[elemTypeRep.HostType]]) { elem => - projectReification(k)(InstanceRep(elemTypeRep)(elem)) + elems <- elements(rep.tpe)(rep.inst) + dims <- forEach(dimensions(rep.tpe)(rep.inst)) { dim => + reify(k)(InstanceRep(TypeRep.Int)(dim)) } - elemType <- projectResolution(k)(elemTypeRep) - res <- Apply[CreateArray[Type], Expression, Expression](CreateArray(elemType), elems).interpret(canCreateArray) + elemType <- elementType(rep.tpe)(rep.inst) + res <- CreateArray[Type,Expression](elemType, dims, Some(dimensions(rep.tpe)(rep.inst),elems)).interpret(using canCreateArray) } yield res + + } case _ => reify(k)(rep) } diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Assertions.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Assertions.scala index dc4be600..394eac5e 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Assertions.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Assertions.scala @@ -41,7 +41,7 @@ class Assertions[AP <: AnyParadigm](val base: AP)(ooParadigm: ObjectOriented[AP] } override def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Booleans.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Booleans.scala index 538e4fee..89f120ba 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Booleans.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Booleans.scala @@ -12,7 +12,6 @@ import org.combinators.cogen.TypeRep import org.combinators.cogen.paradigm.Apply import org.combinators.cogen.paradigm.ffi.{And, False, Not, Or, True, Booleans as Bools} - class Booleans[Ctxt, AP <: AnyParadigm](val base: AP) extends Bools[Ctxt] { case object BooleansEnabled @@ -44,7 +43,7 @@ class Booleans[Ctxt, AP <: AnyParadigm](val base: AP) extends Bools[Ctxt] { } } def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Console.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Console.scala index 946965e8..d2e758b8 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Console.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Console.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.java.paradigm.ffi /*DI:LD:AI*/ +package org.combinators.ep.language.java.paradigm.ffi /*DI:LD:AI*/ import com.github.javaparser.ast.NodeList import com.github.javaparser.ast.expr.{FieldAccessExpr, MethodCallExpr, NameExpr, SimpleName} @@ -25,7 +25,7 @@ class Console[Ctxt, AP <: AnyParadigm]( ): (Ctxt, Expression) = { (context, new MethodCallExpr(new FieldAccessExpr(new NameExpr(new SimpleName("System")), "out"), "println", new NodeList(command.arguments.head)) - ) + ) } } } diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Equality.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Equality.scala index 9224e793..b9ae39c5 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Equality.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Equality.scala @@ -49,16 +49,17 @@ class Equality[Ctxt, AP <: AnyParadigm]( } } } - def enable(): Generator[base.ProjectContext, Unit] = Enable.interpret(new Understands[base.ProjectContext, Enable.type] { - def perform( - context: ProjectCtxt, - command: Enable.type - ): (ProjectCtxt, Unit) = { - if (!context.resolver.resolverInfo.contains(EqualityEnabled)) { - val resolverUpdate = - ContextSpecificResolver.updateResolver(base.config, TypeRep.Boolean, PrimitiveType.booleanType())(new BooleanLiteralExpr(_)) - (context.copy(resolver = resolverUpdate(context.resolver).addInfo(EqualityEnabled)), ()) - } else (context, ()) - } - }) + def enable(): Generator[base.ProjectContext, Unit] = + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { + def perform( + context: ProjectCtxt, + command: Enable.type + ): (ProjectCtxt, Unit) = { + if (!context.resolver.resolverInfo.contains(EqualityEnabled)) { + val resolverUpdate = + ContextSpecificResolver.updateResolver(base.config, TypeRep.Boolean, PrimitiveType.booleanType())(new BooleanLiteralExpr(_)) + (context.copy(resolver = resolverUpdate(context.resolver).addInfo(EqualityEnabled)), ()) + } else (context, ()) + } + }) } diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Exceptions.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Exceptions.scala index 6dae5d82..aaf14bbe 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Exceptions.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Exceptions.scala @@ -5,7 +5,7 @@ import com.github.javaparser.ast.expr.ObjectCreationExpr import com.github.javaparser.ast.stmt.ThrowStmt import org.combinators.cogen.paradigm.ffi import org.combinators.cogen.Command.Generator -import org.combinators.cogen.paradigm.ffi.{Assert, Exceptions as Excptns} +import org.combinators.cogen.paradigm.ffi.Exceptions as Excptns import org.combinators.cogen.Understands import org.combinators.ep.language.java.CodeGenerator.Enable import org.combinators.ep.language.java.Syntax.default._ @@ -14,8 +14,8 @@ import org.combinators.ep.language.java.{MethodBodyCtxt, ProjectCtxt} class Exceptions[AP <: AnyParadigm](val base: AP) extends Excptns[MethodBodyCtxt] { - val exceptionCapabilities: ExceptionCapabilities = - new ExceptionCapabilities { + val exceptionsCapabilities: ExceptionsCapabilities = + new ExceptionsCapabilities { override implicit val canRaise: Understands[MethodBodyCtxt, ffi.Exception[Expression, Statement]] = { new Understands[MethodBodyCtxt, ffi.Exception[Expression, Statement]] { def perform( @@ -31,7 +31,7 @@ class Exceptions[AP <: AnyParadigm](val base: AP) extends Excptns[MethodBodyCtxt } override def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Lists.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Lists.scala index 1b7d2150..2ad8965f 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Lists.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Lists.scala @@ -43,7 +43,7 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { ) def toStream(exp: Expression): Expression = - new MethodCallExpr(exp,"stream") + new MethodCallExpr(exp, "stream") def listCreation[Ctxt](canAddImport: Understands[Ctxt, AddImport[Import]]): Understands[Ctxt, Apply[Create[Type], Expression, Expression]] = new Understands[Ctxt, Apply[Create[Type], Expression, Expression]] { @@ -54,11 +54,11 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { val gen: Generator[Ctxt, Expression] = if (command.arguments.isEmpty) { for { - _ <- AddImport[Import](new ImportDeclaration("java.util.Collections", false, false)).interpret(canAddImport) + _ <- AddImport[Import](new ImportDeclaration("java.util.Collections", false, false)).interpret(using canAddImport) } yield new MethodCallExpr(ObjectOriented.nameToExpression(ObjectOriented.fromComponents("java", "util", "Collections")), "emptyList") } else { for { - _ <- AddImport[Import](new ImportDeclaration("java.util.Arrays", false, false)).interpret(canAddImport) + _ <- AddImport[Import](new ImportDeclaration("java.util.Arrays", false, false)).interpret(using canAddImport) } yield new MethodCallExpr(ObjectOriented.nameToExpression(ObjectOriented.fromComponents("java", "util", "Arrays")), "asList", new NodeList[Expression](command.arguments*)) } Command.runGenerator[Ctxt, Expression](gen, context) @@ -79,8 +79,8 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { ): (Ctxt, Expression) = { val gen: Generator[Ctxt, Expression] = for { - _ <- AddImport[Import](streamImp).interpret(addImport) - _ <- AddImport[Import](collectorsImp).interpret(addImport) + _ <- AddImport[Import](streamImp).interpret(using addImport) + _ <- AddImport[Import](collectorsImp).interpret(using addImport) } yield { streamCollect( streamConcat( @@ -133,8 +133,8 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { ): (Ctxt, Expression) = { val gen: Generator[Ctxt, Expression] = for { - _ <- AddImport[Import](streamImp).interpret(addImport) - _ <- AddImport[Import](collectorsImp).interpret(addImport) + _ <- AddImport[Import](streamImp).interpret(using addImport) + _ <- AddImport[Import](collectorsImp).interpret(using addImport) } yield streamCollect( streamConcat( @@ -148,7 +148,7 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { } def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type @@ -168,7 +168,7 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { case TypeRep.Sequence(elemRep) => for { elemType <- projectResolution(k)(elemRep) - resultType <- Apply[Type, Type, Type](listType, Seq(elemType)).interpret(canApplyType) + resultType <- Apply[Type, Type, Type](listType, Seq(elemType)).interpret(using canApplyType) } yield resultType case other => toResolution(k)(other) } @@ -186,7 +186,7 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] { projectReiification(k)(InstanceRep(elemTypeRep)(elem)) } elemType <- projectResolution(k)(elemTypeRep) - res <- Apply[Create[Type], Expression, Expression](Create(elemType), elems).interpret(canCreateList) + res <- Apply[Create[Type], Expression, Expression](Create(elemType), elems).interpret(using canCreateList) } yield res case _ => reify(k)(rep) } @@ -252,21 +252,21 @@ object Lists { val generics: Gen } def apply[Ctxt, AP <: AnyParadigm, Gen[A <: AP] <: Generics[A]]( - base: AP, - applyType: Understands[Ctxt, Apply[Type, Type, Type]], - addImport: Understands[Ctxt, AddImport[Import]])( - generics: Gen[base.type] - ): Aux[Ctxt, base.type, generics.type] = { + base: AP, + applyType: Understands[Ctxt, Apply[Type, Type, Type]], + addImport: Understands[Ctxt, AddImport[Import]])( + generics: Gen[base.type] + ): Aux[Ctxt, base.type, generics.type] = { val b: base.type = base val appTy = applyType val addImp = addImport val gen: generics.type = generics case class Lsts(override val base: b.type, - override val applyType: Understands[Ctxt, Apply[Type, Type, Type]], - override val addImport: Understands[Ctxt, AddImport[Import]], - override val generics: gen.type - ) extends Lists[Ctxt, b.type] + override val applyType: Understands[Ctxt, Apply[Type, Type, Type]], + override val addImport: Understands[Ctxt, AddImport[Import]], + override val generics: gen.type + ) extends Lists[Ctxt, b.type] Lsts(b, appTy, addImp, gen) } diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Maps.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Maps.scala new file mode 100644 index 00000000..7d582a62 --- /dev/null +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Maps.scala @@ -0,0 +1,304 @@ +package org.combinators.ep.language.java.paradigm.ffi /*DI:LD:AI*/ + +import com.github.javaparser.ast.`type`.{ClassOrInterfaceType, Type} +import com.github.javaparser.ast.body.InitializerDeclaration +import com.github.javaparser.ast.expr.{MethodCallExpr, ObjectCreationExpr, ThisExpr, TypeExpr} +import com.github.javaparser.ast.stmt.{BlockStmt, ExpressionStmt} +import org.combinators.cogen.Command.Generator +import org.combinators.cogen.{Command, InstanceRep, TypeRep, Understands} +import org.combinators.ep.language.java.CodeGenerator.Enable +import org.combinators.ep.language.java.{ContextSpecificResolver, JavaNameProvider, ProjectCtxt} +import org.combinators.ep.language.java.paradigm.{AnyParadigm, Generics, ObjectOriented} +import org.combinators.ep.language.java.Syntax.default.* +import org.combinators.cogen.paradigm.AnyParadigm.syntax.* +import com.github.javaparser.ast.{ImportDeclaration, NodeList} +import org.combinators.cogen.paradigm.control.{DeclareVariable, LiftExpression} +import org.combinators.cogen.paradigm.ffi.{ContainsKey, CreateMap, GetOrElse, Put, Maps as Mps} +import org.combinators.cogen.paradigm.{AddBlockDefinitions, AddImport, Apply, FreshName} + +trait Maps[Ctxt, AP <: AnyParadigm] extends Mps[Ctxt] { + case object MapsEnabled + + val base: AP + + val generics: Generics[base.type] + val canAddImport: Understands[Ctxt, AddImport[Import]] + val canApplyType: Understands[Ctxt, Apply[Type, Type, Type]] + val canFreshName: Understands[Ctxt, FreshName[Name]] + val canDeclareVariable: Understands[Ctxt, DeclareVariable[Name, Type, Option[Expression], Expression]] + val canLiftExpression: Understands[Ctxt, LiftExpression[Expression, Statement]] + val canAddBlockDefinitions: Understands[Ctxt, AddBlockDefinitions[Statement]] + + val mapImp = new ImportDeclaration("java.util.Map", false, false) + val hashMapImp = new ImportDeclaration("java.util.HashMap", false, false) + + def createMap[Ctxt](canAddImport : Understands[Ctxt, AddImport[Import]]) : Understands[Ctxt, Apply[CreateMap[Type], (Expression,Expression), Expression]] = + new Understands[Ctxt, Apply[CreateMap[Type], (Expression,Expression), Expression]] { + def perform( + context: Ctxt, + command: Apply[CreateMap[Type], (Expression,Expression), Expression] + ): (Ctxt, Expression) = { + + val mapType = ObjectOriented.nameToType(mapImp.getName) + + val classScope = new TypeExpr(mapType) + val entries = command.arguments.map({ + case (key, value) => + new MethodCallExpr(classScope, "entry", new NodeList(key, value)) + }) + + val boxedKeyType = if (command.functional.keyType.isPrimitiveType) { + command.functional.keyType.asPrimitiveType().toBoxedType + } else { + command.functional.keyType + } + val boxedElemType = if (command.functional.elementType.isPrimitiveType) { + command.functional.elementType.asPrimitiveType().toBoxedType + } else { + command.functional.elementType + } + + val gen = for { + _ <- AddImport(mapImp).interpret(canAddImport) + } yield new MethodCallExpr( + classScope, + new NodeList(boxedKeyType, boxedElemType), + "ofEntries", + new NodeList(entries*)) + + Command.runGenerator(gen, context) + } + } + + def putIntoMap[Ctxt]( + canAddImport : Understands[Ctxt, AddImport[Import]], + canApplyType: Understands[Ctxt, Apply[Type, Type, Type]], + canFreshName: Understands[Ctxt, FreshName[Name]], + canDeclareVariable: Understands[Ctxt, DeclareVariable[Name, Type, Option[Expression], Expression]], + canLiftExpression: Understands[Ctxt, LiftExpression[Expression, Statement]], + canAddBlockDefinitions: Understands[Ctxt, AddBlockDefinitions[Statement]] + ) : Understands[Ctxt, Apply[Put[Type], Expression, Expression]] = + new Understands[Ctxt, Apply[Put[Type], Expression, Expression]] { + override def perform( + context: Ctxt, + command: Apply[Put[Type], Expression, Expression] + ): (Ctxt, Expression) = { + val hashMapType = ObjectOriented.nameToType(hashMapImp.getName) + val mapType = ObjectOriented.nameToType(mapImp.getName) + + val gen = for { + _ <- AddImport(hashMapImp).interpret(canAddImport) + tmp <- FreshName(JavaNameProvider.mangle("tmp")).interpret(canFreshName) + appliedMapTpe <- Apply(mapType, Seq(command.functional.keyType, command.functional.valueType)).interpret(canApplyType) + appliedHashMapTpe <- Apply(hashMapType, Seq(command.functional.keyType, command.functional.valueType)).interpret(canApplyType) + newMap = new ObjectCreationExpr( + null, + appliedHashMapTpe.asInstanceOf[ClassOrInterfaceType], + new NodeList[Expression](command.arguments.head), + ) + tmpVar <- DeclareVariable(tmp, appliedMapTpe, Some(newMap)).interpret(canDeclareVariable) + putStmt <- LiftExpression(new MethodCallExpr( + tmpVar, + "put", + new NodeList[Expression](command.arguments(1), command.arguments(2)) + )).interpret(canLiftExpression) + _ <- AddBlockDefinitions(Seq(putStmt)).interpret(canAddBlockDefinitions) + } yield tmpVar + + Command.runGenerator(gen, context) + } + } + + val mapCapabilities: MapCapabilities = + new MapCapabilities { + + implicit val canCreate: Understands[Ctxt, Apply[CreateMap[Type], (Expression,Expression), Expression]] = createMap(canAddImport) + + implicit val canContainsKey: Understands[Ctxt, Apply[ContainsKey, Expression, Expression]] = + new Understands[Ctxt, Apply[ContainsKey, Expression, Expression]] { + def perform( + context: Ctxt, + command: Apply[ContainsKey, Expression, Expression] + ): (Ctxt, Expression) = { + (context, new MethodCallExpr(command.arguments(0), "containsKey", new NodeList[Expression](command.arguments(1)))) + } + } + + implicit val canGet: Understands[Ctxt, Apply[GetOrElse, Expression, Expression]] = + new Understands[Ctxt, Apply[GetOrElse, Expression, Expression]] { + def perform( + context: Ctxt, + command: Apply[GetOrElse, Expression, Expression] + ): (Ctxt, Expression) = { + (context, new MethodCallExpr(command.arguments(0), "getOrDefault", new NodeList[Expression](command.arguments(1), command.arguments(2)))) + } + } + + implicit val canPut: Understands[Ctxt, Apply[Put[Type], Expression, Expression]] = + putIntoMap(canAddImport, + canApplyType, + canFreshName, + canDeclareVariable, + canLiftExpression, + canAddBlockDefinitions) + } + + def enable(): Generator[base.ProjectContext, Unit] = + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { + def perform( + context: ProjectCtxt, + command: Enable.type + ): (ProjectCtxt, Unit) = { + if (!context.resolver.resolverInfo.contains(MapsEnabled)) { + + val mapName = ObjectOriented.fromComponents("java", "util", "Map") + val mapType = ObjectOriented.nameToType(mapName) + val mapImp = new ImportDeclaration(mapName, false, false) + + val hashMapName = ObjectOriented.fromComponents("java", "util", "HashMap") + val hashMapType = ObjectOriented.nameToType(hashMapName) + val hashMapImp = new ImportDeclaration(hashMapName, false, false) + + def updateResolver(resolver: ContextSpecificResolver): ContextSpecificResolver = { + def addResolutionType[Ctxt]( + toResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type], + projectResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type], + canApplyType: Understands[Ctxt, Apply[Type, Type, Type]] + ): ContextSpecificResolver => TypeRep => Generator[Ctxt, Type] = k => { + case TypeRep.Map(keyRep, elemRep) => + for { + keyType <- projectResolution(k)(keyRep) + elemType <- projectResolution(k)(elemRep) + boxedKeyType = if (keyType.isPrimitiveType) { keyType.asPrimitiveType().toBoxedType } else { keyType } + boxedElemType = if (elemType.isPrimitiveType) { elemType.asPrimitiveType().toBoxedType } else { elemType } + resultType <- Apply[Type, Type, Type](mapType, Seq(boxedKeyType, boxedElemType)).interpret(using canApplyType) + } yield resultType + case other => toResolution(k)(other) + } + + def addReification[Ctxt]( + reify: ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression], + projectResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type], + projectReiification: ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression], + canCreateMap: Understands[Ctxt, Apply[CreateMap[Type], (Expression, Expression), Expression]] + ): ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression] = + k => rep => rep.tpe match { + case TypeRep.Map(keyTypeRep, elemTypeRep) => + for { + elems <- forEach(rep.inst.asInstanceOf[Map[keyTypeRep.HostType, elemTypeRep.HostType]].toSeq) { case (key,value) => + for { + reifiedKey <- projectReiification(k) (InstanceRep(keyTypeRep) (key)) + reifiedValue <- projectReiification(k) (InstanceRep(elemTypeRep) (value)) + } yield (reifiedKey, reifiedValue) + } + keyType <- projectResolution(k)(keyTypeRep) + elemType <- projectResolution(k)(elemTypeRep) + + res <- Apply[CreateMap[Type], (Expression, Expression), Expression](CreateMap(keyType, elemType), elems).interpret(using canCreateMap) + } yield res + case _ => reify(k)(rep) + } + + def addExtraImport( + importResolution: ContextSpecificResolver => Type => Option[Import] + ): ContextSpecificResolver => Type => Option[Import] = k => { + case tpe + if AnyParadigm.stripGenerics(tpe) + .toClassOrInterfaceType + .map[Boolean](clsTy => clsTy.getNameWithScope == mapType.asClassOrInterfaceType().getNameWithScope) + .orElse(false) => + Some(mapImp) + + case tpe + if AnyParadigm.stripGenerics(tpe) + .toClassOrInterfaceType + .map[Boolean](clsTy => clsTy.getNameWithScope == hashMapType.asClassOrInterfaceType().getNameWithScope) + .orElse(false) => + Some(hashMapImp) + + case other => importResolution(k)(other) + } + + resolver.copy( + _methodTypeResolution = + addResolutionType( + resolver._methodTypeResolution, + _.methodTypeResolution, + generics.ppolyParadigm.methodBodyCapabilities.canApplyTypeInMethod + ), + _constructorTypeResolution = + addResolutionType( + resolver._constructorTypeResolution, + _.constructorTypeResolution, + generics.constructorCapabilities.canApplyTypeInConstructor + ), + _classTypeResolution = + addResolutionType( + resolver._classTypeResolution, + _.classTypeResolution, + generics.classCapabilities.canApplyTypeInClass + ), + _reificationInConstructor = + addReification( + resolver._reificationInConstructor, + _.constructorTypeResolution, + _.reificationInConstructor, + createMap(generics.ooParadigm.constructorCapabilities.canAddImportInConstructor) + ), + _reificationInMethod = + addReification( + resolver._reificationInMethod, + _.methodTypeResolution, + _.reificationInMethod, + createMap(base.methodBodyCapabilities.canAddImportInMethodBody) + ), + _importResolution = addExtraImport(resolver._importResolution) + ).addInfo(MapsEnabled) + } + + + (context.copy(resolver = updateResolver(context.resolver)), ()) + } else (context, ()) + } + }) +} + +object Maps { + type Aux[Ctxt, AP <: AnyParadigm, Gen <: Generics[AP]] = Maps[Ctxt, AP] { + val generics: Gen + } + def apply[Ctxt, AP <: AnyParadigm, Gen[A <: AP] <: Generics[A]]( + base: AP, + addImport: Understands[Ctxt, AddImport[Import]], + canApplyType: Understands[Ctxt, Apply[Type, Type, Type]], + canFreshName: Understands[Ctxt, FreshName[Name]], + canDeclareVariable: Understands[Ctxt, DeclareVariable[Name, Type, Option[Expression], Expression]], + canLiftExpression: Understands[Ctxt, LiftExpression[Expression, Statement]], + canAddBlockDefinitions: Understands[Ctxt, AddBlockDefinitions[Statement]] + ) + ( + generics: Gen[base.type] + ): Aux[Ctxt, base.type, generics.type] = { + val b: base.type = base + val addImp = addImport + val applyType = canApplyType + val freshName = canFreshName + val declareVar = canDeclareVariable + val liftExp = canLiftExpression + val addBlockDfn = canAddBlockDefinitions + val gen: generics.type = generics + + case class Mps( + override val base: b.type, + override val generics: gen.type, + override val canAddImport: Understands[Ctxt, AddImport[Import]], + override val canApplyType: Understands[Ctxt, Apply[Type, Type, Type]], + override val canFreshName: Understands[Ctxt, FreshName[Name]], + override val canDeclareVariable: Understands[Ctxt, DeclareVariable[Name, Type, Option[Expression], Expression]], + override val canLiftExpression: Understands[Ctxt, LiftExpression[Expression, Statement]], + override val canAddBlockDefinitions: Understands[Ctxt, AddBlockDefinitions[Statement]] + ) extends Maps[Ctxt, b.type] + + Mps(b, gen, addImp, applyType, freshName, declareVar, liftExp, addBlockDfn) + } +} \ No newline at end of file diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/RealArithmetic.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/RealArithmetic.scala index bbd9ffc8..aed6ea3e 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/RealArithmetic.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/RealArithmetic.scala @@ -5,7 +5,7 @@ import com.github.javaparser.ast.expr.BinaryExpr.Operator import com.github.javaparser.ast.expr.{BinaryExpr, Expression, FieldAccessExpr, MethodCallExpr} import org.combinators.cogen.TypeRep import org.combinators.cogen.paradigm.Apply -import org.combinators.cogen.paradigm.ffi.{Abs, Cos, EulersNumber, Floor, Log, Pi, Pow, Sin, Sqrt, RealArithmetic as RArith} +import org.combinators.cogen.paradigm.ffi.{Abs, Cos, EulersNumber, Floor, Log, Min, Max, Pi, Pow, Sin, Sqrt, RealArithmetic as RArith} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, Understands} import org.combinators.ep.language.java.CodeGenerator.Enable @@ -13,7 +13,6 @@ import org.combinators.ep.language.java.Syntax.default._ import org.combinators.ep.language.java.paradigm.{AnyParadigm, ObjectOriented} import org.combinators.ep.language.java.{ContextSpecificResolver, ProjectCtxt} - class RealArithmetic[Ctxt, T, AP <: AnyParadigm]( val base: AP, rep: TypeRep.OfHostType[T], @@ -55,6 +54,26 @@ class RealArithmetic[Ctxt, T, AP <: AnyParadigm]( } } + private def javaMathMaxOp[Ctxt, Op](): Understands[Ctxt, Apply[Op, Expression, Expression]] = + new Understands[Ctxt, Apply[Op, Expression, Expression]] { + def perform( + context: Ctxt, + command: Apply[Op, Expression, Expression] + ): (Ctxt, Expression) = { + (context, new MethodCallExpr(mathExp, "max", new NodeList[Expression](command.arguments*))) + } + } + + private def javaMathMinOp[Ctxt, Op](): Understands[Ctxt, Apply[Op, Expression, Expression]] = + new Understands[Ctxt, Apply[Op, Expression, Expression]] { + def perform( + context: Ctxt, + command: Apply[Op, Expression, Expression] + ): (Ctxt, Expression) = { + (context, new MethodCallExpr(mathExp, "min", new NodeList[Expression](command.arguments*))) + } + } + private def javaMathConst[Ctxt, Const <: Command.WithResult[Expression]](constName: String): Understands[Ctxt, Const] = new Understands[Ctxt, Const] { def perform( @@ -73,6 +92,10 @@ class RealArithmetic[Ctxt, T, AP <: AnyParadigm]( javaMathOp("pow") implicit val canLog: Understands[Ctxt, Apply[Log[T], Expression, Expression]] = javaMathLogOp() + implicit val canMax: Understands[Ctxt, Apply[Max[T], Expression, Expression]] = + javaMathMaxOp() + implicit val canMin: Understands[Ctxt, Apply[Min[T], Expression, Expression]] = + javaMathMinOp() implicit val canSin: Understands[Ctxt, Apply[Sin[T], Expression, Expression]] = javaMathOp("sin") implicit val canCos: Understands[Ctxt, Apply[Cos[T], Expression, Expression]] = @@ -88,7 +111,7 @@ class RealArithmetic[Ctxt, T, AP <: AnyParadigm]( } def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type diff --git a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Strings.scala b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Strings.scala index 5e62ad55..5b7cbc14 100644 --- a/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Strings.scala +++ b/language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Strings.scala @@ -1,6 +1,6 @@ package org.combinators.ep.language.java.paradigm.ffi /*DI:LD:AI*/ -import com.github.javaparser.ast.expr.{BinaryExpr, MethodCallExpr, StringLiteralExpr} +import com.github.javaparser.ast.expr.{BinaryExpr, MethodCallExpr, StringLiteralExpr, CharLiteralExpr} import org.combinators.cogen.Command.Generator import org.combinators.cogen.{Command, Understands} import org.combinators.ep.language.java.{CodeGenerator, ContextSpecificResolver, JavaNameProvider, ProjectCtxt, Syntax} @@ -10,7 +10,7 @@ import CodeGenerator.Enable import com.github.javaparser.ast.NodeList import org.combinators.cogen.TypeRep import org.combinators.cogen.paradigm.{Apply, GetMember} -import org.combinators.cogen.paradigm.ffi.{GetStringLength, StringAppend, ToString, Strings as Strs} +import org.combinators.cogen.paradigm.ffi.{GetCharAt, GetStringLength, StringAppend, SubString, ToString, Strings as Strs} class Strings[Ctxt, AP <: AnyParadigm]( val base: AP, @@ -36,6 +36,39 @@ class Strings[Ctxt, AP <: AnyParadigm]( Command.runGenerator(gen, context) } } + + implicit val canGetCharAt: Understands[Ctxt, Apply[GetCharAt, Expression, Expression]] = + new Understands[Ctxt, Apply[GetCharAt, Expression, Expression]] { + def perform( + context: Ctxt, + command: Apply[GetCharAt, Expression, Expression] + ): (Ctxt, Expression) = { + implicit val _getMember = getMember + implicit val _applyMethod = applyMethod + val gen = for { + charAtMethod <- GetMember[Expression, Name](command.arguments(0), JavaNameProvider.mangle("charAt")).interpret + res <- Apply[Expression, Expression, Expression](charAtMethod, Seq(command.arguments(1))).interpret + } yield res + Command.runGenerator(gen, context) + } + } + + implicit val canSubString: Understands[Ctxt, Apply[SubString, Expression, Expression]] = + new Understands[Ctxt, Apply[SubString, Expression, Expression]] { + def perform( + context: Ctxt, + command: Apply[SubString, Expression, Expression] + ): (Ctxt, Expression) = { + implicit val _getMember = getMember + implicit val _applyMethod = applyMethod + val gen = for { + substringMethod <- GetMember[Expression, Name](command.arguments(0), JavaNameProvider.mangle("substring")).interpret + res <- Apply[Expression, Expression, Expression](substringMethod, Seq(command.arguments(1), command.arguments(2))).interpret + } yield res + Command.runGenerator(gen, context) + } + } + implicit val canAppend: Understands[Ctxt, Apply[StringAppend, Expression, Expression]] = new Understands[Ctxt, Apply[StringAppend, Expression, Expression]] { def perform( @@ -62,15 +95,18 @@ class Strings[Ctxt, AP <: AnyParadigm]( } def enable(): Generator[base.ProjectContext, Unit] = - Enable.interpret(new Understands[base.ProjectContext, Enable.type] { + Enable.interpret(using new Understands[base.ProjectContext, Enable.type] { def perform( context: ProjectCtxt, command: Enable.type ): (ProjectCtxt, Unit) = { if (!context.resolver.resolverInfo.contains(StringsEnabled)) { + // heineman: until we have a top-level FFI Character, then sneak in type for Character here. val resolverUpdate = ContextSpecificResolver.updateResolver(base.config, TypeRep.String, ObjectOriented.nameToType(ObjectOriented.fromComponents("String")))(new StringLiteralExpr(_)) - (context.copy(resolver = resolverUpdate(context.resolver).addInfo(StringsEnabled)), ()) + val resolverCharUpdate = + ContextSpecificResolver.updateResolver(base.config, TypeRep.Char, ObjectOriented.nameToType(ObjectOriented.fromComponents("Character")))(new CharLiteralExpr(_)) + (context.copy(resolver = resolverCharUpdate(resolverUpdate(context.resolver)).addInfo(StringsEnabled)), ()) } else (context, ()) } }) diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/BaseAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/BaseAST.scala index c072a900..f1aa051d 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/BaseAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/BaseAST.scala @@ -1,9 +1,8 @@ -package org.combinators.ep.language.scala.ast +package org.combinators.ep.language.scala.ast /*DI:LD:AI*/ import org.combinators.cogen.Command.Generator import org.combinators.cogen.TypeRep.OfHostType import org.combinators.cogen.{FileWithPath, NameProvider, TypeRep} -import org.combinators.ep.language.inbetween.functional import org.combinators.ep.language.inbetween.functional.FunctionalAST import org.combinators.ep.language.inbetween.functional.control.FunctionalControlAST import org.combinators.ep.language.inbetween.imperative.ImperativeAST @@ -12,7 +11,6 @@ import org.combinators.ep.language.inbetween.polymorphism.generics.GenericsAST import java.util.UUID - trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalControlAST with ImperativeAST with NameProviderAST { object scalaBase { object anyOverrides { @@ -225,7 +223,7 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC override def emptyPatternCtxt: funcontrol.PatternContext = functionalControlFactory.patternContext(Seq.empty) def addTestExpressions(exprs: Seq[any.Expression]): any.Method = { - copy(statements = exprs.map(liftExpression)) + copy(statements = statements ++ exprs.map(liftExpression)) } def findClass(qualifiedName: any.Name*): any.Type = @@ -287,7 +285,8 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC underlyingClass.addParent(classReferenceType( Seq("org", "scalatest", "funsuite", "AnyFunSuite").map(n => nameProvider.mangle(n)) * )) - val methodsAsTests = withFunSuiteExtension.methods.zip(this.testMarkers).filter { case (m, isTest) => isTest }.map { case (m, _) => { + + val methodsAsTests = withFunSuiteExtension.methods.zip(this.testMarkers).filter { case (m, isTest) => isTest }.map { case (m, _) => liftExpression(applyExpression( applyExpression( memberAccessExpression(selfReferenceExpression, nameProvider.mangle("test")), @@ -295,7 +294,7 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC ), Seq(blockExpression(m.statements)) )) - } + } val withPrimaryClsConstructor = if (underlyingClass.constructors.isEmpty) { withFunSuiteExtension.addConstructor(constructor(statements = methodsAsTests)) @@ -1053,6 +1052,7 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC trait FinalTypes extends imperative.FinalTypes { type DeclareVariable <: imperativeOverrides.DeclareVariable type AssignVariable <: imperativeOverrides.AssignVariable + type Tertiary <: imperativeOverrides.Tertiary type IfThenElse <: imperativeOverrides.IfThenElse type While <: imperativeOverrides.While type VariableReferenceExpression <: imperativeOverrides.VariableReferenceExpression @@ -1062,6 +1062,7 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC import factory.* def toScala: String = { val init = this.initializer.map(ie => s" = ${ie.toScala}").getOrElse("") + assert(!init.isBlank) // CANNOT be blank for Scala var s""" |var ${this.name.toScala}: ${this.tpe.toScala}$init |""".stripMargin @@ -1088,6 +1089,28 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC copy(assignmentExpression = assignmentExpression.prefixRootPackage(rootPackageName, excludedTypeNames)) } + trait Tertiary extends imperative.Tertiary with anyOverrides.Expression { + import factory.* + + def toScala: String = { + + s""" + |if (${condition.toScala}) { + | ${trueExpression.toScala} + |} else { + | ${falseExpression.toScala} + |} + """.stripMargin + } + + def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): imperative.Tertiary = + copy( + condition = condition.prefixRootPackage(rootPackageName, excludedTypeNames), + trueExpression = trueExpression.prefixRootPackage(rootPackageName, excludedTypeNames), + falseExpression = falseExpression.prefixRootPackage(rootPackageName, excludedTypeNames) + ) + } + trait IfThenElse extends imperative.IfThenElse with anyOverrides.Statement { import factory.* @@ -1196,6 +1219,8 @@ trait BaseAST extends OOAST with FunctionalAST with GenericsAST with FunctionalC value.asInstanceOf[Seq[t.elemTpe.HostType]].map(v => reifiedScalaValue(t.elemTpe, v).toScala).mkString("Seq(", ", ", ")") case t: TypeRep.Array[_] => value.asInstanceOf[Array[t.elemTpe.HostType]].map(v => reifiedScalaValue(t.elemTpe, v).toScala).mkString("Array(", ", ", ")") + case t: TypeRep.Char.type => s"""'$value'""" + case _ => value.toString } @@ -1385,6 +1410,7 @@ trait FinalBaseAST extends BaseAST { type DeclareVariable = imperativeOverrides.DeclareVariable type AssignVariable = imperativeOverrides.AssignVariable + type Tertiary = imperativeOverrides.Tertiary type IfThenElse = imperativeOverrides.IfThenElse type While = imperativeOverrides.While type VariableReferenceExpression = imperativeOverrides.VariableReferenceExpression @@ -1768,6 +1794,21 @@ trait FinalBaseAST extends BaseAST { } LiftExpression(expression) } + + def tertiary(condition: any.Expression, + trueExpression: any.Expression, + falseExpression: any.Expression): imperative.Tertiary = { + case class Tertiary( + override val condition: any.Expression, + override val trueExpression: any.Expression, + override val falseExpression: any.Expression) + extends scalaBase.imperativeOverrides.Tertiary + with finalBaseAST.anyOverrides.FinalExpression { + def getSelfTertiary: imperativeFinalTypes.Tertiary = this + } + Tertiary(condition, trueExpression, falseExpression) + } + def ifThenElse(condition: any.Expression, ifBranch: Seq[any.Statement], elseIfBranches: Seq[(any.Expression, Seq[any.Statement])], @@ -1783,6 +1824,7 @@ trait FinalBaseAST extends BaseAST { } IfThenElse(condition, ifBranch, elseIfBranches, elseBranch) } + def whileLoop(condition: any.Expression, body: Seq[any.Statement]): imperative.While = { case class WhileLoop(override val condition: any.Expression, override val body: Seq[any.Statement]) extends scalaBase.imperativeOverrides.While diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/NameProviderAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/NameProviderAST.scala index 501f7ed4..d70905da 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/NameProviderAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/NameProviderAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast +package org.combinators.ep.language.scala.ast /*DI:LD:AI*/ import com.github.javaparser.{JavaParser, StaticJavaParser} import org.combinators.cogen.NameProvider diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArithmeticAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArithmeticAST.scala index 5a60c138..3b6dff6b 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArithmeticAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArithmeticAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.{ArithmeticAST => InbetweenArithmeticOpsAST} import org.combinators.ep.language.scala.ast.BaseAST diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArraysAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArraysAST.scala new file mode 100644 index 00000000..b30fe6e1 --- /dev/null +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ArraysAST.scala @@ -0,0 +1,237 @@ +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ + +import org.combinators.ep.language.inbetween.ffi.{ArraysAST => InbetweenArraysAST} +import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} + +trait ArraysAST extends InbetweenArraysAST { + self: OperatorExpressionsAST & BaseAST => + object scalaArraysOps { + object arraysOpsOverride { + trait FinalTypes extends arraysOps.FinalTypes { + type Array <: arraysOpsOverride.Array + type CreateArrayExpression <: arraysOpsOverride.CreateArray + type CreateArrayFromExpression <: arraysOpsOverride.CreateArrayFromExpression + type CreateArrayWithDefaultValues <: arraysOpsOverride.CreateArrayWithDefaultValues + type CreateArrayFromValues <: arraysOpsOverride.CreateArrayFromValues + type ArrayExpression <: arraysOpsOverride.ArrayExpression + type LengthArrayExpression <: arraysOpsOverride.LengthArrayExpression + type SetArrayExpression <: arraysOpsOverride.SetArrayExpression + } + + trait Array extends arraysOps.Array with scalaBase.anyOverrides.Type { + override def toScala: String = "Array" + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): Array = + this + override def toImport: Seq[any.Import] = Seq.empty + } + + trait CreateArray extends arraysOps.CreateArray with scalaBase.anyOverrides.Expression { + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): CreateArray + } + + trait CreateArrayFromExpression extends arraysOps.CreateArrayFromExpression with CreateArray { + import factory._ + override def toScala: String = + expression.toScala + + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): CreateArrayFromExpression = + arraysOpsFactory.convert(copy(expression = expression.prefixRootPackage(rootPackageName, excludedTypeNames))) + + override def toImport: Seq[any.Import] = Seq.empty + } + + trait CreateArrayWithDefaultValues extends arraysOps.CreateArrayWithDefaultValues with CreateArray { + import factory._ + import arraysOpsFactory.convert + override def toScala: String + = s"Array.ofDim[${tpe.toScala}](${dimensions.map(_.toScala).mkString(", ")})" + override def prefixRootPackage(rootPackageName: scala.Seq[ArraysAST.this.any.Name], excludedTypeNames: _root_.scala.Predef.Set[scala.Seq[ArraysAST.this.any.Name]]): CreateArrayWithDefaultValues = + copy( + tpe = tpe.prefixRootPackage(rootPackageName, excludedTypeNames), + dimensions = dimensions.map(_.prefixRootPackage(rootPackageName, excludedTypeNames)) + ) + } + + trait CreateArrayFromValues extends arraysOps.CreateArrayFromValues with CreateArray { + import factory._ + import arraysOpsFactory.convert + + override def toScala: String = + s"Array(${values.map(_.toScala).mkString(", ")})" + override def prefixRootPackage(rootPackageName: scala.Seq[ArraysAST.this.any.Name], excludedTypeNames: _root_.scala.Predef.Set[scala.Seq[ArraysAST.this.any.Name]]): CreateArrayFromValues = + copy( + values = values.map(_.prefixRootPackage(rootPackageName, excludedTypeNames)) + ) + } + + trait ArrayExpression extends arraysOps.ArrayExpression + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.PostfixOperator + with scalaBase.anyOverrides.Expression { + import factory._ + import arraysOpsFactory.convert + + override def toScala: String = { + val indexPairs = indices.map(idx => s"(${idx.toScala})").mkString("") + s"${base.toScala}$indexPairs" + } + + override def prefixRootPackage(rootPackageName: scala.Seq[ArraysAST.this.any.Name], excludedTypeNames: _root_.scala.Predef.Set[scala.Seq[ArraysAST.this.any.Name]]): ArrayExpression = + copy( + base = base.prefixRootPackage(rootPackageName, excludedTypeNames), + indices = indices + ) + } + + trait SetArrayExpression extends arraysOps.SetArrayExpression with scalaOperatorExpressions.operatorExpressionsOverrides.Operator with scalaBase.anyOverrides.Statement { + + import factory._ + import arraysOpsFactory.convert + + override def toScala: String = { + val indexPairs = indices.map(idx => s"(${idx.toScala})").mkString("") + s"${base.toScala}${indexPairs} = ${value.toScala}" + } + + override def prefixRootPackage(rootPackageName: scala.Seq[ArraysAST.this.any.Name], excludedTypeNames: _root_.scala.Predef.Set[scala.Seq[ArraysAST.this.any.Name]]): SetArrayExpression = + copy( + base = base.prefixRootPackage(rootPackageName, excludedTypeNames), + indices = indices, + value = value + ) + } + + trait LengthArrayExpression extends arraysOps.LengthArrayExpression + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.PostfixOperator + with scalaBase.anyOverrides.Expression + { + import factory._ + import arraysOpsFactory.convert + + override def toScala: String = { + if (indices.nonEmpty) { + val indexPairs = indices.map(idx => s"(${idx.toScala})").mkString("") + s"${base.toScala}$indexPairs.length" + } else { + s"${base.toScala}.length" + } + } + + override def prefixRootPackage(rootPackageName: scala.Seq[ArraysAST.this.any.Name], excludedTypeNames: _root_.scala.Predef.Set[scala.Seq[ArraysAST.this.any.Name]]): LengthArrayExpression = + copy( + base = base.prefixRootPackage(rootPackageName, excludedTypeNames), + indices = indices + ) + } + + trait Factory extends arraysOps.Factory {} + } + } + + override val arraysOpsFinalTypes: scalaArraysOps.arraysOpsOverride.FinalTypes + override val arraysOpsFactory: scalaArraysOps.arraysOpsOverride.Factory +} + +trait FinalArraysAST extends ArraysAST { self: FinalOperatorExpressionsAST & FinalBaseAST => + object finalArraysFinalTypes { + trait ArraysFinalTypes extends scalaArraysOps.arraysOpsOverride.FinalTypes { + type Array = scalaArraysOps.arraysOpsOverride.Array + type CreateArrayExpression = scalaArraysOps.arraysOpsOverride.CreateArray + type CreateArrayFromExpression = scalaArraysOps.arraysOpsOverride.CreateArrayFromExpression + type CreateArrayWithDefaultValues = scalaArraysOps.arraysOpsOverride.CreateArrayWithDefaultValues + type CreateArrayFromValues = scalaArraysOps.arraysOpsOverride.CreateArrayFromValues + type ArrayExpression = scalaArraysOps.arraysOpsOverride.ArrayExpression + type SetArrayExpression = scalaArraysOps.arraysOpsOverride.SetArrayExpression + type LengthArrayExpression = scalaArraysOps.arraysOpsOverride.LengthArrayExpression + } + } + override val arraysOpsFinalTypes: finalArraysFinalTypes.ArraysFinalTypes = new finalArraysFinalTypes.ArraysFinalTypes {} + + object finalArraysFactoryTypes { + trait FinalArraysFactory extends scalaArraysOps.arraysOpsOverride.Factory { + def array(): arraysOps.Array = { + case class Array() + extends scalaArraysOps.arraysOpsOverride.Array { + override def getSelfArrayType: scalaArraysOps.arraysOpsOverride.Array = this + override def getSelfType: scalaBase.anyOverrides.Type = this + } + Array() + } + + def createArrayFromExpression(expression: any.Expression): scalaArraysOps.arraysOpsOverride.CreateArrayFromExpression = { + case class CreateArrayFromExpression(val expression: any.Expression) + extends scalaArraysOps.arraysOpsOverride.CreateArrayFromExpression + with finalBaseAST.anyOverrides.FinalExpression { + override def getSelfCreateArrayExpression: arraysOpsFinalTypes.CreateArrayExpression = this + override def getSelfCreateArrayFromExpression: arraysOpsFinalTypes.CreateArrayFromExpression = this + } + CreateArrayFromExpression(expression) + } + + def createArrayWithDefaultValues(tpe: any.Type, dimensions: Seq[any.Expression]): scalaArraysOps.arraysOpsOverride.CreateArrayWithDefaultValues = { + case class CreateArrayWithDefaultValues(tpe: any.Type, dimensions: Seq[any.Expression]) + extends scalaArraysOps.arraysOpsOverride.CreateArrayWithDefaultValues + with finalBaseAST.anyOverrides.FinalExpression { + override def getSelfCreateArrayExpression: arraysOpsFinalTypes.CreateArrayExpression = this + override def getSelfCreateArrayWithDefaultValues: arraysOpsFinalTypes.CreateArrayWithDefaultValues = this + } + CreateArrayWithDefaultValues(tpe, dimensions) + } + + def createArrayFromValues(values: Seq[any.Expression]): scalaArraysOps.arraysOpsOverride.CreateArrayFromValues = { + case class CreateArrayFromValues(values: Seq[any.Expression]) + extends scalaArraysOps.arraysOpsOverride.CreateArrayFromValues + with finalBaseAST.anyOverrides.FinalExpression { + override def getSelfCreateArrayExpression: arraysOpsFinalTypes.CreateArrayExpression = this + override def getSelfCreateArrayFromValues: arraysOpsFinalTypes.CreateArrayFromValues = this + } + CreateArrayFromValues(values) + } + + def lengthArrayExpression(base: any.Expression, indices: Seq[any.Expression]): scalaArraysOps.arraysOpsOverride.LengthArrayExpression = { + case class LengthArrayExpression(base: any.Expression, indices: Seq[any.Expression]) + extends scalaArraysOps.arraysOpsOverride.LengthArrayExpression + with finalOperatorExpressions.operatorExpressionsOverrides.Operator + with finalBaseAST.anyOverrides.FinalExpression { + def operator: String = ".length" + + override def getSelfLengthArrayExpression: scalaArraysOps.arraysOpsOverride.LengthArrayExpression = this + override def getSelfExpression: finalBaseAST.anyOverrides.FinalExpression = this + } + + LengthArrayExpression(base, indices) + } + + def arrayExpression(base: any.Expression, indices: Seq[any.Expression]): scalaArraysOps.arraysOpsOverride.ArrayExpression = { + case class ArrayExpression(base: any.Expression, indices: Seq[any.Expression]) + extends scalaArraysOps.arraysOpsOverride.ArrayExpression + with finalOperatorExpressions.operatorExpressionsOverrides.Operator + with finalBaseAST.anyOverrides.FinalExpression { + + override def getSelfArrayExpression: scalaArraysOps.arraysOpsOverride.ArrayExpression = this + override def getSelfExpression: finalBaseAST.anyOverrides.FinalExpression = this + + override def operator: String = ".apply" + } + ArrayExpression(base, indices) + } + + def setArrayExpression(base: any.Expression, indices: Seq[any.Expression], value: any.Expression): scalaArraysOps.arraysOpsOverride.SetArrayExpression = { + case class SetArrayExpression(base: any.Expression, indices: Seq[any.Expression], value: any.Expression) + extends scalaArraysOps.arraysOpsOverride.SetArrayExpression + with finalOperatorExpressions.operatorExpressionsOverrides.Operator + with finalBaseAST.anyOverrides.FinalExpression { + override def toScala(operands: any.Expression*): String = ??? + + override def getSelfSetArrayExpression: scalaArraysOps.arraysOpsOverride.SetArrayExpression = this + override def getSelfStatement: finalTypes.Statement = this + + } + SetArrayExpression(base, indices, value) + } + } + } + + val arraysOpsFactory: finalArraysFactoryTypes.FinalArraysFactory = new finalArraysFactoryTypes.FinalArraysFactory {} +} diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/AssertionsAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/AssertionsAST.scala index 7252ed4f..ce6df4c7 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/AssertionsAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/AssertionsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.{AssertionsAST => InbetweenAssertionsAST} import org.combinators.ep.language.scala.ast.BaseAST diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/BooleanAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/BooleanAST.scala index 1ead8c05..b1238604 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/BooleanAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/BooleanAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.{BooleanAST => InbetweenBooleanAST} import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ConsoleAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ConsoleAST.scala new file mode 100644 index 00000000..3acaf652 --- /dev/null +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ConsoleAST.scala @@ -0,0 +1,37 @@ +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ + +import org.combinators.ep.language.inbetween.ffi.{ConsoleAST => InbetweenConsoleAST} +import org.combinators.ep.language.scala.ast.BaseAST +import org.combinators.ep.language.scala.ast.ffi.OperatorExpressionsAST + +trait ConsoleAST extends InbetweenConsoleAST { self: OperatorExpressionsAST & BaseAST => + object scalaConsole { + object consoleOpsOverride { + trait ConsolePrintOp extends consoleOps.ConsolePrintOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator { + import factory.* + def operator: String = "println " + def toScala(operands: any.Expression*): String = s"println (${operands.head.toScala})" + } + + trait Factory extends consoleOps.Factory {} + } + } + val consoleOpsFactory: scalaConsole.consoleOpsOverride.Factory +} + +trait FinalConsoleAST extends ConsoleAST { self: FinalOperatorExpressionsAST & BaseAST => + object finalConsoleFactoryTypes { + trait ConsoleFactory extends scalaConsole.consoleOpsOverride.Factory { + def consolePrintOp(): scalaConsole.consoleOpsOverride.ConsolePrintOp = { + case class ConsolePrintOp() extends scalaConsole.consoleOpsOverride.ConsolePrintOp { + + def getSelfOperator: operatorExpressionsFinalTypes.Operator = this + } + + ConsolePrintOp() + } + } + } + + val consoleOpsFactory: finalConsoleFactoryTypes.ConsoleFactory = new finalConsoleFactoryTypes.ConsoleFactory {} +} \ No newline at end of file diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/EqualsAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/EqualsAST.scala index 086e10fe..4c5c8c65 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/EqualsAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/EqualsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.{EqualsAST => InbetweenEqualsAST} import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ExceptionsAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ExceptionsAST.scala new file mode 100644 index 00000000..cd8096d7 --- /dev/null +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ExceptionsAST.scala @@ -0,0 +1,37 @@ +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ + +import org.combinators.ep.language.inbetween.ffi.{ExceptionsAST => InbetweenExceptionsAST} +import org.combinators.ep.language.scala.ast.BaseAST +import org.combinators.ep.language.scala.ast.ffi.OperatorExpressionsAST + +trait ExceptionsAST extends InbetweenExceptionsAST { self: OperatorExpressionsAST & BaseAST => + object scalaExceptions { + object exceptionsOpsOverride { + trait ExceptionsRaiseOp extends exceptionsOps.RaiseOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator { + import factory.* + def operator: String = "raise " + def toScala(operands: any.Expression*): String = s"raise ${operands.head.toScala}" + } + + trait Factory extends exceptionsOps.Factory {} + } + } + val exceptionsOpsFactory: scalaExceptions.exceptionsOpsOverride.Factory +} + +trait FinalExceptionsAST extends ExceptionsAST { self: FinalOperatorExpressionsAST & BaseAST => + object finalExceptionsFactoryTypes { + trait ExceptionsFactory extends scalaExceptions.exceptionsOpsOverride.Factory { + def raiseOp(): scalaExceptions.exceptionsOpsOverride.ExceptionsRaiseOp = { + case class Raise() extends scalaExceptions.exceptionsOpsOverride.ExceptionsRaiseOp { + + def getSelfOperator: operatorExpressionsFinalTypes.Operator = this + } + + Raise() + } + } + } + + val exceptionsOpsFactory: finalExceptionsFactoryTypes.ExceptionsFactory = new finalExceptionsFactoryTypes.ExceptionsFactory {} +} \ No newline at end of file diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ListsAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ListsAST.scala index 57322391..73b56842 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ListsAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/ListsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.ListsAST as InbetweenListsAST import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/MapsAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/MapsAST.scala new file mode 100644 index 00000000..ca05c55c --- /dev/null +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/MapsAST.scala @@ -0,0 +1,134 @@ +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ + +import org.combinators.ep.language.inbetween.ffi.MapsAST as InbetweenMapsAST +import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} +import org.combinators.cogen.TypeRep + +trait MapsAST extends InbetweenMapsAST { self: OperatorExpressionsAST & BaseAST => + object scalaMapsOps { + object mapsOpsOverride { + trait FinalTypes extends mapsOps.FinalTypes { + type Map <: mapsOpsOverride.Map + type CreateMapExpression <: mapsOpsOverride.CreateMap + } + + trait Map extends mapsOps.Map with scalaBase.anyOverrides.Type { + import factory.convert + override def toScala: String = s"Map" + + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): mapsOps.Map = this + + def toImport: Seq[any.Import] = Seq.empty + } + + trait CreateMap extends mapsOps.CreateMap with scalaBase.anyOverrides.Expression { + import factory.convert + override def toScala: String = { + val inits = initialKeyValuePairs.map({ case (k, v) => s"${k.toScala} -> ${v.toScala}"}).mkString(", ") + s"Map[${keyType.toScala},${elementType.toScala}]($inits)" + } + + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): mapsOps.CreateMap = + copy(keyType = keyType.prefixRootPackage(rootPackageName, excludedTypeNames), + elementType = elementType.prefixRootPackage(rootPackageName, excludedTypeNames), + initialKeyValuePairs = initialKeyValuePairs.map({ case (k,v) => + (k.prefixRootPackage(rootPackageName, excludedTypeNames), v.prefixRootPackage(rootPackageName, excludedTypeNames))} + )) + } + + trait ContainsKeyOp extends mapsOps.ContainsKeyOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator { + import factory.convert + def operator: String = ".containsKey" + + override def toScala(operands: any.Expression*): String = { + val base = operands(0).toScala + val key = operands(1).toScala + + s"$base.contains($key)" + } + } + + trait GetOp extends mapsOps.GetOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator { + import factory.convert + + override def toScala(operands: any.Expression*): String = { + val base = operands(0).toScala + val key = operands(1).toScala + val defaultValue = operands(2).toScala + + s"$base.getOrElse($key, $defaultValue)" + } + } + + trait PutOp extends mapsOps.PutOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator { + import factory.convert + + override def toScala(operands: any.Expression*): String = { + val base = operands(0).toScala + val key = operands(1).toScala + val value = operands(2).toScala + + s"$base.updated($key, $value)" + } + + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): mapsOps.PutOp = + copy(keyType = keyType.prefixRootPackage(rootPackageName, excludedTypeNames), + elementType = elementType.prefixRootPackage(rootPackageName, excludedTypeNames)) + } + + trait Factory extends mapsOps.Factory {} + } + } + + override val mapsOpsFactory: scalaMapsOps.mapsOpsOverride.Factory +} + +trait FinalMapsAST extends MapsAST { self: FinalOperatorExpressionsAST & FinalBaseAST => + object finalMapsFinalTypes { + trait MapsFinalTypes extends scalaMapsOps.mapsOpsOverride.FinalTypes { + type Map = scalaMapsOps.mapsOpsOverride.Map + type CreateMapExpression = scalaMapsOps.mapsOpsOverride.CreateMap + } + } + + override val mapsOpsFinalTypes: finalMapsFinalTypes.MapsFinalTypes = new finalMapsFinalTypes.MapsFinalTypes {} + + object finalMapsFactoryTypes { + trait FinalMapsFactory extends scalaMapsOps.mapsOpsOverride.Factory { + + override def map() : mapsOps.Map = { + case class Map() extends scalaMapsOps.mapsOpsOverride.Map { + override def getSelfType: scalaBase.anyOverrides.Type = this + override def getSelfMapType: scalaMapsOps.mapsOpsOverride.Map = this + } + Map() + } + + override def createMap(keyType:any.Type, elementType:any.Type, initialKeyValuePairs: Seq[(any.Expression,any.Expression)] + ): mapsOps.CreateMap = { + case class CreateMap(keyType:any.Type, elementType:any.Type, initialKeyValuePairs: Seq[(any.Expression,any.Expression)]) extends + scalaMapsOps.mapsOpsOverride.CreateMap with finalBaseAST.anyOverrides.FinalExpression{ + override def getSelfCreateMapExpression: scalaMapsOps.mapsOpsOverride.CreateMap = this + } + CreateMap(keyType, elementType, initialKeyValuePairs) + } + + def containsKeyOp(): mapsOps.ContainsKeyOp = { + case class ContainsKeyOp() extends scalaMapsOps.mapsOpsOverride.ContainsKeyOp with finalOperatorExpressions.operatorExpressionsOverrides.Operator + ContainsKeyOp() + } + + def getOp(): mapsOps.GetOp = { + case class GetOp() extends scalaMapsOps.mapsOpsOverride.GetOp with finalOperatorExpressions.operatorExpressionsOverrides.Operator + GetOp() + } + + override def putOp(keyType: any.Type, elementType: any.Type): mapsOps.PutOp = { + case class PutOp(keyType: any.Type, elementType: any.Type) extends scalaMapsOps.mapsOpsOverride.PutOp with finalOperatorExpressions.operatorExpressionsOverrides.Operator + PutOp(keyType, elementType) + } + } + } + + val mapsOpsFactory: finalMapsFactoryTypes.FinalMapsFactory = new finalMapsFactoryTypes.FinalMapsFactory {} +} diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/OperatorExpressionsAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/OperatorExpressionsAST.scala index 26539fa9..fb60a90c 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/OperatorExpressionsAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/OperatorExpressionsAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.{OperatorExpressionOpsAST => InbetweenOperatorExpressionOpsAST} import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} @@ -8,16 +8,31 @@ trait OperatorExpressionsAST extends InbetweenOperatorExpressionOpsAST{ self: Ba object operatorExpressionsOverrides { trait FinalTypes extends operatorExpressions.FinalTypes { type Operator <: operatorExpressionsOverrides.Operator + type TernaryExpression <: operatorExpressionsOverrides.TernaryExpression type BinaryExpression <: operatorExpressionsOverrides.BinaryExpression type UnaryExpression <: operatorExpressionsOverrides.UnaryExpression } + trait TernaryExpression extends scalaBase.anyOverrides.Expression with operatorExpressions.TernaryExpression { + + def toScala: String = s"(${operator.getSelfOperator.toScala(left, mid, right)})" // necessary when composing expressions, though can get excessive at times. + + override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): operatorExpressions.TernaryExpression = + copy( + operator = operator.getSelfOperator.prefixRootPackage(rootPackageName, excludedTypeNames), + left = left.getSelfExpression.prefixRootPackage(rootPackageName, excludedTypeNames), + mid = mid.getSelfExpression.prefixRootPackage(rootPackageName, excludedTypeNames), + right = right.getSelfExpression.prefixRootPackage(rootPackageName, excludedTypeNames) + ) + } + trait BinaryExpression extends scalaBase.anyOverrides.Expression with operatorExpressions.BinaryExpression { def toScala: String = s"(${operator.getSelfOperator.toScala(left, right)})" // necessary when composing expressions, though can get excessive at times. override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): operatorExpressions.BinaryExpression = copy( + operator = operator.getSelfOperator.prefixRootPackage(rootPackageName, excludedTypeNames), left = left.getSelfExpression.prefixRootPackage(rootPackageName, excludedTypeNames), right = right.getSelfExpression.prefixRootPackage(rootPackageName, excludedTypeNames) ) @@ -28,12 +43,15 @@ trait OperatorExpressionsAST extends InbetweenOperatorExpressionOpsAST{ self: Ba override def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): operatorExpressions.UnaryExpression = copy( + operator = operator.getSelfOperator.prefixRootPackage(rootPackageName, excludedTypeNames), operand = operand.getSelfExpression.prefixRootPackage(rootPackageName, excludedTypeNames) ) } trait Operator extends operatorExpressions.Operator { def toScala(operands: any.Expression*): String + + def prefixRootPackage(rootPackageName: Seq[any.Name], excludedTypeNames: Set[Seq[any.Name]]): operatorExpressions.Operator = this } trait Factory extends operatorExpressions.Factory {} @@ -81,6 +99,7 @@ trait FinalOperatorExpressionsAST extends OperatorExpressionsAST { self: FinalBa object finalOperatorExpressionsFinalTypes { trait OperatorExpressionsFinalTypes extends scalaOperatorExpressions.operatorExpressionsOverrides.FinalTypes { type Operator = scalaOperatorExpressions.operatorExpressionsOverrides.Operator + type TernaryExpression = scalaOperatorExpressions.operatorExpressionsOverrides.TernaryExpression type BinaryExpression = scalaOperatorExpressions.operatorExpressionsOverrides.BinaryExpression type UnaryExpression = scalaOperatorExpressions.operatorExpressionsOverrides.UnaryExpression } @@ -89,6 +108,19 @@ trait FinalOperatorExpressionsAST extends OperatorExpressionsAST { self: FinalBa object finalOperatorExpressionsFactoryTypes { trait OperatorExpressionsFactory extends scalaOperatorExpressions.operatorExpressionsOverrides.Factory { + def ternaryExpression(operator: operatorExpressions.Operator, left: any.Expression, mid: any.Expression, right: any.Expression): operatorExpressions.TernaryExpression = { + case class TernaryExpression( + override val operator: operatorExpressions.Operator, + override val left: any.Expression, + override val mid: any.Expression, + override val right: any.Expression) + extends scalaOperatorExpressions.operatorExpressionsOverrides.TernaryExpression + with finalBaseAST.anyOverrides.FinalExpression { + def getSelfTernaryExpression: scalaOperatorExpressions.operatorExpressionsOverrides.TernaryExpression = this + } + TernaryExpression(operator, left, mid, right) + } + def binaryExpression(operator: operatorExpressions.Operator, left: any.Expression, right: any.Expression): operatorExpressions.BinaryExpression = { case class BinaryExpression( override val operator: operatorExpressions.Operator, @@ -100,6 +132,7 @@ trait FinalOperatorExpressionsAST extends OperatorExpressionsAST { self: FinalBa } BinaryExpression(operator, left, right) } + def unaryExpression(operator: operatorExpressions.Operator, operand: any.Expression): operatorExpressions.UnaryExpression = { case class UnaryExpression( override val operator: operatorExpressions.Operator, diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/RealArithmeticAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/RealArithmeticAST.scala index 33bcee0e..6519e365 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/RealArithmeticAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/RealArithmeticAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.RealArithmeticAST as InbetweenRealArithmeticAST import org.combinators.ep.language.scala.ast.{BaseAST, FinalBaseAST} @@ -31,6 +31,27 @@ trait RealArithmeticOpsAST extends InbetweenRealArithmeticAST { self: OperatorEx } } + trait MaxOp extends realArithmeticOps.MaxOp + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.MathFunctionOperator { + import factory.* + override def operator: String = "max" + + override def toScala(operands: any.Expression*): String = { + s"(Math.$operator(${operands(0).toScala}, ${operands(1).toScala}))" + } + } + + trait MinOp extends realArithmeticOps.MinOp + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.MathFunctionOperator { + import factory.* + override def operator: String = "min" + override def toScala(operands: any.Expression*): String = { + s"(Math.$operator(${operands(0).toScala}, ${operands(1).toScala}))" + } + } + trait SinOp extends realArithmeticOps.SinOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator with scalaOperatorExpressions.MathFunctionOperator { @@ -93,6 +114,16 @@ trait FinalRealArithmeticOpsAST extends RealArithmeticOpsAST { self: FinalOperat with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} LogOp() } + def maxOp(): realArithmeticOps.MaxOp = { + case class MaxOp() extends scalaRealArithmeticOps.realArithmeticOpsOverride.MaxOp + with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} + MaxOp() + } + def minOp(): realArithmeticOps.MinOp = { + case class MinOp() extends scalaRealArithmeticOps.realArithmeticOpsOverride.MinOp + with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} + MinOp() + } def sinOp(): realArithmeticOps.SinOp = { case class SinOp() extends scalaRealArithmeticOps.realArithmeticOpsOverride.SinOp with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/StringAST.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/StringAST.scala index 7d3df25b..3d289867 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/StringAST.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/ast/ffi/StringAST.scala @@ -1,4 +1,4 @@ -package org.combinators.ep.language.scala.ast.ffi +package org.combinators.ep.language.scala.ast.ffi /*DI:LD:AI*/ import org.combinators.ep.language.inbetween.ffi.StringAST as InbetweenStringsAST import org.combinators.ep.language.scala.ast.BaseAST @@ -8,24 +8,44 @@ trait StringAST extends InbetweenStringsAST { self: OperatorExpressionsAST & Bas object scalaStringOps { object stringOpsOverride { - trait ToStringOp extends stringOps.ToStringOp - with scalaOperatorExpressions.operatorExpressionsOverrides.Operator - with scalaOperatorExpressions.PostfixOperator { - override def operator: String = ".toString()" - } - trait AppendStringOp extends stringOps.AppendStringOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator with scalaOperatorExpressions.InfixOperator { override def operator: String = "++" } + trait GetCharAtOp extends stringOps.GetCharAtOp + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.InfixOperator { + override def operator: String = s".charAt" + } + trait StringLengthOp extends stringOps.StringLengthOp with scalaOperatorExpressions.operatorExpressionsOverrides.Operator with scalaOperatorExpressions.PostfixOperator { override def operator: String = ".length" } - + + trait SubStringOp extends stringOps.SubStringOp + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.PostfixOperator { + override def operator: String = { + ".substring" + } + + override def toScala(operands: any.Expression*): String = { + val base = operands.head.getSelfExpression.toScala + val ops = operands.tail.map(arg => arg.getSelfExpression.toScala).mkString(",") + s"${base}.substring($ops)" + } + } + + trait ToStringOp extends stringOps.ToStringOp + with scalaOperatorExpressions.operatorExpressionsOverrides.Operator + with scalaOperatorExpressions.PostfixOperator { + override def operator: String = ".toString()" + } + trait Factory extends stringOps.Factory {} } } @@ -36,21 +56,31 @@ trait StringAST extends InbetweenStringsAST { self: OperatorExpressionsAST & Bas trait FinalStringAST extends StringAST { self: FinalOperatorExpressionsAST & BaseAST => object finalStringsFactoryTypes { trait FinalStringsFactory extends scalaStringOps.stringOpsOverride.Factory { - def toStringOp(): stringOps.ToStringOp = { - case class ToStringOp() extends scalaStringOps.stringOpsOverride.ToStringOp - with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} - ToStringOp() - } def appendStringOp(): stringOps.AppendStringOp = { case class AppendStringOp() extends scalaStringOps.stringOpsOverride.AppendStringOp with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} AppendStringOp() } + def getCharAtOp(): stringOps.GetCharAtOp = { + case class GetCharAtOp() extends scalaStringOps.stringOpsOverride.GetCharAtOp + with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} + GetCharAtOp() + } def stringLengthOp(): stringOps.StringLengthOp = { case class StringLengthOp() extends scalaStringOps.stringOpsOverride.StringLengthOp with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} StringLengthOp() } + def subStringOp(): stringOps.SubStringOp = { + case class SubStringOp() extends scalaStringOps.stringOpsOverride.SubStringOp + with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} + SubStringOp() + } + def toStringOp(): stringOps.ToStringOp = { + case class ToStringOp() extends scalaStringOps.stringOpsOverride.ToStringOp + with finalOperatorExpressions.operatorExpressionsOverrides.Operator {} + ToStringOp() + } } } diff --git a/language/newScala/src/main/scala/org/combinators/ep/language/scala/codegen/CodeGenerator.scala b/language/newScala/src/main/scala/org/combinators/ep/language/scala/codegen/CodeGenerator.scala index c61afa27..c27b13dd 100644 --- a/language/newScala/src/main/scala/org/combinators/ep/language/scala/codegen/CodeGenerator.scala +++ b/language/newScala/src/main/scala/org/combinators/ep/language/scala/codegen/CodeGenerator.scala @@ -1,6 +1,4 @@ -package org.combinators.ep.language.scala.codegen - -/*DI:LD:AI*/ +package org.combinators.ep.language.scala.codegen /*DI:LD:AI*/ import cats.Apply as _ import org.combinators.cogen.Command.Generator @@ -22,11 +20,15 @@ import java.nio.file.{Path, Paths} type FullAST = BaseAST & NameProviderAST + & ArraysAST & ArithmeticAST & AssertionsAST & BooleanAST + & ConsoleAST + & ExceptionsAST & EqualsAST & ListsAST + & MapsAST & OperatorExpressionOpsAST & RealArithmeticAST & StringAST @@ -55,6 +57,27 @@ sealed class CodeGenerator[AST <: FullAST](val domainName: String, val ast: AST, case TypeRep.Boolean => toLookup("Boolean") case TypeRep.String => toLookup("String") case TypeRep.Unit => toLookup("Unit") + case TypeRep.Array(elemTpe) => + Some( + for { + elemTpe <- ToTargetLanguageType[ast.any.Type](elemTpe).interpret(canToTargetLanguage) + arrayTpe <- Command.lift(ast.arraysOpsFactory.array()) + tpe <- Apply[ + ast.any.Type, + ast.any.Type, + ast.any.Type](arrayTpe, Seq(elemTpe)).interpret(canApplyType) + } yield tpe) + case TypeRep.Map(keyTpe, elemTpe) => + Some( + for { + keyTpe <- ToTargetLanguageType[ast.any.Type](keyTpe).interpret(canToTargetLanguage) + elemTpe <- ToTargetLanguageType[ast.any.Type](elemTpe).interpret(canToTargetLanguage) + mapTpe <- Command.lift(ast.mapsOpsFactory.map()) + tpe <- Apply[ + ast.any.Type, + ast.any.Type, + ast.any.Type](mapTpe, Seq(keyTpe, elemTpe)).interpret(canApplyType) + } yield tpe) case TypeRep.Sequence(elemTpeRep) => Some( for { @@ -82,9 +105,11 @@ sealed class CodeGenerator[AST <: FullAST](val domainName: String, val ast: AST, def prefixExcludedTypes: Set[Seq[ast.any.Name]] = { Set( + Seq("Array"), Seq("Double"), Seq("Boolean"), Seq("Int"), + Seq("Map"), Seq("Unit"), Seq("String"), Seq("Seq"), @@ -170,11 +195,9 @@ sealed class CodeGenerator[AST <: FullAST](val domainName: String, val ast: AST, )(functional.typeCapabilities.canTranslateTypeInType, parametricPolymorphismInADTContexts.algebraicDataTypeCapabilities.canApplyTypeInADT) - val (generatedProject, _) = Command.runGenerator(generator, projectWithLookups) val withPrefix = ast.factory.convert(generatedProject).prefixRootPackage(Seq(nameProvider.mangle(domainName)), prefixExcludedTypes) - def toFileWithPath(cu: ast.any.CompilationUnit, basePath: Path): FileWithPath = { FileWithPath(ast.factory.convert(cu).toScala, { val nameAsStrings = cu.name.map(name => ast.factory.convert(name).toScala) @@ -215,11 +238,11 @@ sealed class CodeGenerator[AST <: FullAST](val domainName: String, val ast: AST, val generics: Generics.WithBase[ast.type, paradigm.type, ooParadigm.type, parametricPolymorphism.type] = Generics[ast.type, paradigm.type, ooParadigm.type, parametricPolymorphism.type](paradigm, ooParadigm, parametricPolymorphism) val parametricPolymorphismInADTContexts: ParametricPolymorphismInADTContexts.WithBase[ast.type, paradigm.type, functional.type] = ParametricPolymorphismInADTContexts[ast.type, paradigm.type, functional.type](paradigm, functional) - + val arrays: Arrays.WithBase[ast.type, paradigm.type] = Arrays[ast.type, paradigm.type](paradigm) val booleans: Booleans.WithBase[ast.type, paradigm.type] = Booleans[ast.type, paradigm.type](paradigm) val doubles: Arithmetic.WithBase[Double, ast.type, paradigm.type] = Arithmetic[Double, ast.type, paradigm.type](paradigm) - + val console: Console.WithBase[ast.type, paradigm.type] = Console[ast.type, paradigm.type](paradigm) val realDoubles: RealArithmetic.WithBase[Double, ast.type, paradigm.type] = RealArithmetic[Double, ast.type, paradigm.type](paradigm) val ints: Arithmetic.WithBase[Int, ast.type, paradigm.type] = Arithmetic[Int, ast.type, paradigm.type](paradigm) @@ -228,51 +251,11 @@ sealed class CodeGenerator[AST <: FullAST](val domainName: String, val ast: AST, val equality: Equals.WithBase[ast.type, paradigm.type] = Equals[ast.type, paradigm.type](paradigm) - /*val consoleInMethod = - new Console[MethodBodyCtxt, paradigm.type]( - paradigm, stringsInMethod - ) - - val consoleInConstructor = - new Console[CtorCtxt, paradigm.type]( - paradigm, stringsInConstructor - ) - - val arraysInMethod = - new Arrays[MethodBodyCtxt, paradigm.type]( - paradigm - ) - - val arraysInConstructor = - new Arrays[CtorCtxt, paradigm.type]( - paradigm - ) - */ - val lists: Lists.WithBase[ast.type, paradigm.type] = Lists[ast.type, paradigm.type](paradigm) - - /*val listsInConstructor = - Lists[CtorCtxt, paradigm.type, generics.type]( - paradigm, - ooParadigm.constructorCapabilities.canGetMemberInConstructor, - ooParadigm.constructorCapabilities.canApplyInConstructor, - generics.constructorCapabilities.canApplyTypeInConstructor, - ooParadigm.constructorCapabilities.canAddImportInConstructor - )(generics) - */ - -/* - val treesInConstructor = - Trees[CtorCtxt, paradigm.type, ObjectOriented]( - paradigm, - ooParadigm.constructorCapabilities.canAddImportInConstructor - )(ooParadigm) - - val assertionsInMethod = new Assertions[paradigm.type](paradigm)(ooParadigm) - val exceptionsInMethod = new Exceptions[paradigm.type](paradigm)*/ + val maps: Maps.WithBase[ast.type, paradigm.type] = Maps[ast.type, paradigm.type](paradigm) val assertions = Assertions[ast.type, paradigm.type](paradigm) - + val exceptions: Exceptions.WithBase[ast.type, paradigm.type] = Exceptions[ast.type, paradigm.type](paradigm) } object CodeGenerator { @@ -281,7 +264,6 @@ object CodeGenerator { type Result = Unit } - def apply[AST <: FullAST](domainName: String, ast: AST, additionalPrefixExcludedTypes: Set[Seq[ast.any.Name]] = Set.empty): CodeGenerator[ast.type] = new CodeGenerator[ast.type](domainName, ast, additionalPrefixExcludedTypes) } diff --git a/scripts/AllEvolutions.txt b/scripts/AllEvolutions.txt index 80ab8dd2..2f6c4a27 100644 --- a/scripts/AllEvolutions.txt +++ b/scripts/AllEvolutions.txt @@ -42,7 +42,7 @@ M2 = M1.getModel.evolve("m2", Seq.empty, Seq(PrettyP)) M2_ABS = M2.getModel.evolve("m2_abs", Seq(Abs), Seq.empty) M3 = M2.getModel.evolve("m3", Seq(Neg, Mult, Divd), Seq.empty) M3I1 = M3.getModel.extend("m3i1", Seq(I1.getModel)) -M3W1 = M3.getModel.extend("m3w1", Seq(W1.getModel)) +M3W1 = M3.getModel.extend("m3w1", Seq(W1.getModel)) M4 = M3.getModel.evolve("m4", Seq.empty, Seq(Simplify, Collect)) M5 = M4.getModel.evolve("m5", Seq.empty, Seq(Operation.asTree, Identifier)) M6 = M5.getModel.evolve("m6", Seq.empty, Seq(Equals,Eql) ++ isOps(allTypes)) diff --git a/scripts/README.md b/scripts/README.md index d4959561..db427e61 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -29,6 +29,10 @@ For simplicity, all instructions using the 'sbt' command line. * ep-java-third-alternate (GenerateAllThirdAlternate) * Approaches: oo visitor visitorSideEffect extensibleVisitor interpreter coco trivially dispatch algebra * Evolutions: M0 X1 X2 X3 X2X3 X4 + + * ep-java-quick (QuickValidation) -- Note that you cannot validate this generation (so skip step 2 below) + * Approaches: trivially oo visitor extensibleVisitor interpreter coco algebra + * Evolutions: A3 D3 I2M3I1N1 J8 M9 O1OA O2 OD3 OO3 V1 For Scala-generated code, the above are replaced with `ep-scala-XXX` and approaches and evolutions remain the same. @@ -128,6 +132,8 @@ or source code, executing the test cases and code coverage statistics. This script also detects errors in these three phases. + Make sure `scipy` is installed + In the respective ep-java-XXX directories, execute the following Python script: ```c:\Python37\python.exe ..\..\scripts\process.py > STATISTICS```