text:
package org.apache.pdfbox.pdmodel.interactive.annotation.handlers;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.contentstream.operator.OperatorName;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdmodel.PDAppearanceContentStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationFreeText;
import static org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLine.LE_NONE;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderEffectDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.layout.AppearanceStyle;
import org.apache.pdfbox.pdmodel.interactive.annotation.layout.PlainText;
import org.apache.pdfbox.pdmodel.interactive.annotation.layout.PlainTextFormatter;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.util.Matrix;

public class PDFreeTextAppearanceHandler extends PDAbstractAppearanceHandler
{
    private static final Log LOG = LogFactory.getLog(PDFreeTextAppearanceHandler.class);

    private static final Pattern COLOR_PATTERN =
            Pattern.compile(".*color\\:\\s*\\#([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]).*");

    private float fontSize = 10;
    private COSName fontName = COSName.HELV;

    public PDFreeTextAppearanceHandler(PDAnnotation annotation)
    {
        super(annotation);
    }

    public PDFreeTextAppearanceHandler(PDAnnotation annotation, PDDocument document)
    {
        super(annotation, document);
    }

    @Override
    public void generateNormalAppearance()
    {
        PDAnnotationFreeText annotation = (PDAnnotationFreeText) getAnnotation();
        float[] pathsArray;
        if (PDAnnotationFreeText.IT_FREE_TEXT_CALLOUT.equals(annotation.getIntent()))
        {
            pathsArray = annotation.getCallout();
            if (pathsArray == null || pathsArray.length != 4 && pathsArray.length != 6)
            {
                pathsArray = new float[0];
            }
        }
        else
        {
            pathsArray = new float[0];
        }
        AnnotationBorder ab = AnnotationBorder.getAnnotationBorder(annotation, annotation.getBorderStyle());

        try (PDAppearanceContentStream cs = getNormalAppearanceAsContentStream(true))
        {
            // The fill color is the /C entry, there is no /IC entry defined
            boolean hasBackground = cs.setNonStrokingColorOnDemand(annotation.getColor());
            setOpacity(cs, annotation.getConstantOpacity());

            // Adobe uses the last non stroking color from /DA as stroking color!
            // But if there is a color in /DS, then that one is used for text.
            PDColor strokingColor = extractNonStrokingColor(annotation);
            boolean hasStroke = cs.setStrokingColorOnDemand(strokingColor);
            PDColor textColor = strokingColor;
            String defaultStyleString = annotation.getDefaultStyleString();
            if (defaultStyleString != null)
            {
                Matcher m = COLOR_PATTERN.matcher(defaultStyleString);
                if (m.find())
                {
                    int color = Integer.parseInt(m.group(1), 16);
                    float r = ((color >> 16) & 0xFF) / 255f;
                    float g = ((color >> 8) & 0xFF) / 255f;
                    float b = (color & 0xFF) / 255f;
                    textColor = new PDColor( new float[] { r, g, b }, PDDeviceRGB.INSTANCE);
                }
            }

            if (ab.dashArray != null)
            {
                cs.setLineDashPattern(ab.dashArray, 0);
            }
            cs.setLineWidth(ab.width);

            // draw callout line(s)
            // must be done before retangle paint to avoid a line cutting through cloud
            // see CTAN-example-Annotations.pdf
            for (int i = 0; i < pathsArray.length / 2; ++i)
            {
                float x = pathsArray[i * 2];
                float y = pathsArray[i * 2 + 1];
                if (i == 0)
                {
                    if (SHORT_STYLES.contains(annotation.getLineEndingStyle()))
                    {
                        // modify coordinate to shorten the segment
                        // https://stackoverflow.com/questions/7740507/extend-a-line-segment-a-specific-distance
                        float x1 = pathsArray[2];
                        float y1 = pathsArray[3];
                        float len = (float) (Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2)));
                        if (Float.compare(len, 0) != 0)
                        {
                            x += (x1 - x) / len * ab.width;
                            y += (y1 - y) / len * ab.width;
                        }
                    }
                    cs.moveTo(x, y);
                }
                else
                {
                    cs.lineTo(x, y);
                }
            }
            if (pathsArray.length > 0)
            {
                cs.stroke();
            }

            // paint the styles here and after line(s) draw, to avoid line crossing a filled shape
            if (PDAnnotationFreeText.IT_FREE_TEXT_CALLOUT.equals(annotation.getIntent())
                    // check only needed to avoid q cm Q if LE_NONE
                    && !LE_NONE.equals(annotation.getLineEndingStyle())
                    && pathsArray.length >= 4)
            {
                float x2 = pathsArray[2];
                float y2 = pathsArray[3];
                float x1 = pathsArray[0];
                float y1 = pathsArray[1];
                cs.saveGraphicsState();
                if (ANGLED_STYLES.contains(annotation.getLineEndingStyle()))
                {
                    // do a transform so that first "arm" is imagined flat,
                    // like in line handler.
                    // The alternative would be to apply the transform to the
                    // LE shape coordinates directly, which would be more work
                    // and produce code difficult to understand
                    double angle = Math.atan2(y2 - y1, x2 - x1);
                    cs.transform(Matrix.getRotateInstance(angle, x1, y1));
                }
                else
                {
                    cs.transform(Matrix.getTranslateInstance(x1, y1));
                }
                drawStyle(annotation.getLineEndingStyle(), cs, 0, 0, ab.width, hasStroke, hasBackground, false);
                cs.restoreGraphicsState();
            }

            PDRectangle borderBox;
            PDBorderEffectDictionary borderEffect = annotation.getBorderEffect();
            if (borderEffect != null && borderEffect.getStyle().equals(PDBorderEffectDictionary.STYLE_CLOUDY))
            {
                // Adobe draws the text with the original rectangle in mind.
                // but if there is an /RD, then writing area get smaller.
                // do this here because /RD is overwritten in a few lines
                borderBox = applyRectDifferences(getRectangle(), annotation.getRectDifferences());

                //TODO this segment was copied from square handler. Refactor?
                CloudyBorder cloudyBorder = new CloudyBorder(cs,
                    borderEffect.getIntensity(), ab.width, getRectangle());
                cloudyBorder.createCloudyRectangle(annotation.getRectDifference());
                annotation.setRectangle(cloudyBorder.getRectangle());
                annotation.setRectDifference(cloudyBorder.getRectDifference());
                PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
                appearanceStream.setBBox(cloudyBorder.getBBox());
                appearanceStream.setMatrix(cloudyBorder.getMatrix());
            }
            else
            {
                // handle the border box
                //
                // There are two options. The handling is not part of the PDF specification but
                // implementation specific to Adobe Reader
                // - if /RD is set the border box is the /Rect entry inset by the respective
                //   border difference.
                // - if /RD is not set then we don't touch /RD etc because Adobe doesn't either.
                borderBox = applyRectDifferences(getRectangle(), annotation.getRectDifferences());
                annotation.getNormalAppearanceStream().setBBox(borderBox);

                // note that borderBox is not modified
                PDRectangle paddedRectangle = getPaddedRectangle(borderBox, ab.width / 2);
                cs.addRect(paddedRectangle.getLowerLeftX(), paddedRectangle.getLowerLeftY(),
                           paddedRectangle.getWidth(), paddedRectangle.getHeight());
            }
            cs.drawShape(ab.width, hasStroke, hasBackground);

            // rotation is an undocumented feature, but Adobe uses it. Examples can be found
            // in pdf_commenting_new.pdf file, page 3.
            int rotation = annotation.getCOSObject().getInt(COSName.ROTATE, 0);
            cs.transform(Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0));
            float xOffset;
            float yOffset;
            float width = rotation == 90 || rotation == 270 ? borderBox.getHeight() : borderBox.getWidth();
            // strategy to write formatted text is somewhat inspired by
            // AppearanceGeneratorHelper.insertGeneratedAppearance()
            PDFont font = null;
            float clipY;
            float clipWidth = width - ab.width * 4;
            float clipHeight = rotation == 90 || rotation == 270 ?
                                borderBox.getWidth() - ab.width * 4 : borderBox.getHeight() - ab.width * 4;
            extractFontDetails(annotation);
            if (document != null)
            {
                PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
                if (acroForm != null)
                {
                    // Try to get font from AcroForm default resources
                    // Sample file: https://gitlab.freedesktop.org/poppler/poppler/issues/6
                    PDResources defaultResources = acroForm.getDefaultResources();
                    if (defaultResources != null)
                    {
                        PDFont defaultResourcesFont = defaultResources.getFont(fontName);
                        if (defaultResourcesFont != null)
                        {
                            font = defaultResourcesFont;
                        }
                    }
                }
            }
            if (font == null)
            {
                font = getDefaultFont();
            }
            // value used by Adobe, no idea where it comes from, actual font bbox max y is 0.931
            // gathered by creating an annotation with width 0.
            float yDelta = 0.7896f;
            switch (rotation)
            {
                case 180:
                    xOffset = - borderBox.getUpperRightX() + ab.width * 2;
                    yOffset = - borderBox.getLowerLeftY() - ab.width * 2 - yDelta * fontSize;
                    clipY = - borderBox.getUpperRightY() + ab.width * 2;
                    break;
                case 90:
                    xOffset = borderBox.getLowerLeftY() + ab.width * 2;
                    yOffset = - borderBox.getLowerLeftX() - ab.width * 2 - yDelta * fontSize;
                    clipY = - borderBox.getUpperRightX() + ab.width * 2;
                    break;
                case 270:
                    xOffset = - borderBox.getUpperRightY() + ab.width * 2;
                    yOffset = borderBox.getUpperRightX() - ab.width * 2 - yDelta * fontSize;
                    clipY = borderBox.getLowerLeftX() + ab.width * 2;
                    break;
                case 0:
                default:
                    xOffset = borderBox.getLowerLeftX() + ab.width * 2;
                    yOffset = borderBox.getUpperRightY() - ab.width * 2 - yDelta * fontSize;
                    clipY = borderBox.getLowerLeftY() + ab.width * 2;
                    break;
            }

            // clip writing area
            cs.addRect(xOffset, clipY, clipWidth, clipHeight);
            cs.clip();

            if (annotation.getContents() != null)
            {
                cs.beginText();
                cs.setFont(font, fontSize);
                cs.setNonStrokingColor(textColor.getComponents());
                AppearanceStyle appearanceStyle = new AppearanceStyle();
                appearanceStyle.setFont(font);
                appearanceStyle.setFontSize(fontSize);
                PlainTextFormatter formatter = new PlainTextFormatter.Builder(cs)
                        .style(appearanceStyle)
                        .text(new PlainText(annotation.getContents()))
                        .width(width - ab.width * 4)
                        .wrapLines(true)
                        .initialOffset(xOffset, yOffset)
                        // Adobe ignores the /Q
                        //.textAlign(annotation.getQ())
                        .build();
                try
                {
                    formatter.format();
                }
                catch (IllegalArgumentException ex)
                {
                    throw new IOException(ex);
                }
                finally
                {
                    cs.endText();
                }
            }

            if (pathsArray.length > 0)
            {
                PDRectangle rect = getRectangle();

                // Adjust rectangle
                // important to do this after the rectangle has been painted, because the
                // final rectangle will be bigger due to callout
                // CTAN-example-Annotations.pdf p1
                //TODO in a class structure this should be overridable
                float minX = Float.MAX_VALUE;
                float minY = Float.MAX_VALUE;
                float maxX = Float.MIN_VALUE;
                float maxY = Float.MIN_VALUE;
                for (int i = 0; i < pathsArray.length / 2; ++i)
                {
                    float x = pathsArray[i * 2];
                    float y = pathsArray[i * 2 + 1];
                    minX = Math.min(minX, x);
                    minY = Math.min(minY, y);
                    maxX = Math.max(maxX, x);
                    maxY = Math.max(maxY, y);
                }
                // arrow length is 9 * width at about 30° => 10 * width seems to be enough
                rect.setLowerLeftX(Math.min(minX - ab.width * 10, rect.getLowerLeftX()));
                rect.setLowerLeftY(Math.min(minY - ab.width * 10, rect.getLowerLeftY()));
                rect.setUpperRightX(Math.max(maxX + ab.width * 10, rect.getUpperRightX()));
                rect.setUpperRightY(Math.max(maxY + ab.width * 10, rect.getUpperRightY()));
                annotation.setRectangle(rect);

                // need to set the BBox too, because rectangle modification came later
                annotation.getNormalAppearanceStream().setBBox(getRectangle());

                //TODO when callout is used, /RD should be so that the result is the writable part
            }
        }
        catch (IOException ex)
        {
            LOG.error(ex);
        }
    }

    // get the last non stroking color from the /DA entry
    private PDColor extractNonStrokingColor(PDAnnotationFreeText annotation)
    {
        // It could also work with a regular expression, but that should be written so that
        // "/LucidaConsole 13.94766 Tf .392 .585 .93 rg" does not produce "2 .585 .93 rg" as result
        // Another alternative might be to create a PDDocument and a PDPage with /DA content as /Content,
        // process the whole thing and then get the non stroking color.

        PDColor strokingColor = new PDColor(new float[]{0}, PDDeviceGray.INSTANCE);
        String defaultAppearance = annotation.getDefaultAppearance();
        if (defaultAppearance == null)
        {
            return strokingColor;
        }

        try
        {
            // not sure if charset is correct, but we only need numbers and simple characters
            PDFStreamParser parser = new PDFStreamParser(defaultAppearance.getBytes(StandardCharsets.US_ASCII));
            COSArray arguments = new COSArray();
            COSArray colors = null;
            Operator graphicOp = null;
            for (Object token = parser.parseNextToken(); token != null; token = parser.parseNextToken())
            {
                if (token instanceof Operator)
                {
                    Operator op = (Operator) token;
                    String name = op.getName();
                    if (OperatorName.NON_STROKING_GRAY.equals(name) ||
                        OperatorName.NON_STROKING_RGB.equals(name) ||
                        OperatorName.NON_STROKING_CMYK.equals(name))
                    {
                        graphicOp = op;
                        colors = arguments;
                    }
                    arguments = new COSArray();
                }
                else
                {
                    arguments.add((COSBase) token);
                }
            }
            if (graphicOp != null)
            {
                switch (graphicOp.getName())
                {
                    case OperatorName.NON_STROKING_GRAY:
                        strokingColor = new PDColor(colors, PDDeviceGray.INSTANCE);
                        break;
                    case OperatorName.NON_STROKING_RGB:
                        strokingColor = new PDColor(colors, PDDeviceRGB.INSTANCE);
                        break;
                    case OperatorName.NON_STROKING_CMYK:
                        strokingColor = new PDColor(colors, PDDeviceCMYK.INSTANCE);
                        break;
                    default:
                        break;
                }
            }
        }
        catch (IOException ex)
        {
            LOG.warn("Problem parsing /DA, will use default black", ex);
        }
        return strokingColor;
    }

    //TODO extractNonStrokingColor and extractFontDetails
    // might somehow be replaced with PDDefaultAppearanceString, which is quite similar.
    private void extractFontDetails(PDAnnotationFreeText annotation)
    {
        String defaultAppearance = annotation.getDefaultAppearance();
        if (defaultAppearance == null && document != null)
        {
            PDAcroForm pdAcroForm = document.getDocumentCatalog().getAcroForm();
            if (pdAcroForm != null)
            {
                defaultAppearance = pdAcroForm.getDefaultAppearance();
            }
        }
        if (defaultAppearance == null)
        {
            return;
        }

        try
        {
            // not sure if charset is correct, but we only need numbers and simple characters
            PDFStreamParser parser = new PDFStreamParser(defaultAppearance.getBytes(StandardCharsets.US_ASCII));
            COSArray arguments = new COSArray();
            COSArray fontArguments = new COSArray();
            for (Object token = parser.parseNextToken(); token != null; token = parser.parseNextToken())
            {
                if (token instanceof Operator)
                {
                    Operator op = (Operator) token;
                    String name = op.getName();
                    if (OperatorName.SET_FONT_AND_SIZE.equals(name))
                    {
                        fontArguments = arguments;
                    }
                    arguments = new COSArray();
                }
                else
                {
                    arguments.add((COSBase) token);
                }
            }
            if (fontArguments.size() >= 2)
            {
                COSBase base = fontArguments.get(0);
                if (base instanceof COSName)
                {
                    fontName = (COSName) base;
                }
                base = fontArguments.get(1);
                if (base instanceof COSNumber)
                {
                    fontSize = ((COSNumber) base).floatValue();
                }
            }
        }
        catch (IOException ex)
        {
            LOG.warn("Problem parsing /DA, will use default 'Helv 10'", ex);
        }
    }

    @Override
    public void generateRolloverAppearance()
    {
        // TODO to be implemented
    }

    @Override
    public void generateDownAppearance()
    {
        // TODO to be implemented
    }
}

redpajama_set_name: RedPajamaGithub


Our professionals will work with you to complete repairs on your schedule.
We understand that our clients have busy lives, which is why we strive to make service appointments that are convenient to you. This is just one small example of how we work to earn your trust and your complete satisfaction.
To begin discussing your home maintenance to-do list with one of our friendly and knowledgeable professionals, contact us today.
NOTE: All plumbing and electrical work is performed by licensed contractors.
Copyright © IntelliSight Handymen. All rights reserved.


text:
Q: Change image when using share buttons I'm using the following code to share using custom buttons on my website:

    <img src="images/facebook.png" onclick="popup('http://www.facebook.com/share.php?u=<?php echo $URL; ?>', 'Share on Facebook');">
    <img src="images/twitter.png" onclick="popup('http://twitter.com/intent/tweet?status=<?php echo $coil->name . " at: " . $URL; ?>', 'Share on Twitter');">
    <img src="images/googleplus.png" onclick="popup('https://plus.google.com/share?url=<?php echo $URL; ?>', 'Share on Google+');">

The issue is that when I share the page it selects the image from the button that was clicked. I'm not using any of Twitter's, Facebooks, or google's API's because they don't allow me to use custom images (to my knowledge). I want to define an image for the share to have when someone shares it. How would this be done? Thanks.

A: I added the following meta tags to get it working. From my testing it only works if you have all four of these.
<meta property="og:image" content="url/path/to/image" />
<meta property="og:description" content="Text that will be displayed below title" />
<meta property="og:url"content="URL of page" />
<meta property="og:title" content="Title of shared post" />

If you're having issues you can try to use the Facebook debugger to see what Facebook is seeing. https://developers.facebook.com/tools/debug/

redpajama_set_name: RedPajamaStackExchange


The time has come for me to slow down a bit.
I am on vacation for the summer, and will be returning to continue repairing woodwinds in October. Wishing Jim great success with this new part of his adventure, and wishing all of my many loyal customers a fantastic summer!
Copyright 2015 © Gary Armstrong Woodwinds.


text:
Q: How to implemented this using Repository Pattern (or something more appropriate)? I have a repository called: IChocolateRepository
It derives from a generic repository interface IRepository<> which defines basic repository functions (FindAll, Delete, Add, etc.)
Now, I need to write a piece of code which will go and delete 'all chocolates from the database with expiry data before a supplied date' (assuming that ExpiryDate is a non-nullable property on the Chocolate model class.)
Does this belong in the repository?
Also, how would a sample implementation look like? (I am using EF CTP5)

A: I don't think so.
This does not belong in the Repository but in a class that operates the Transactions using these Repositories.
Unless this is just too simple application where avoiding a separate layer to avoid complexity would be much better.

A: If you already have Remove(T item) method in base interface then
 it won't hurt if you add Remove(Predicate<'T'> condition) to satisfy your needs.
Therefore instead of deleting one particular item you can have a very generic interface to delete everything that satisfies the given predicate.

A: I had a small project (FYP for university degree) and due to time constraints and that i didn't know better I added my more complex data methods to the repository, hard coded.
Personally I would use Andrei Taptunov idea with predicates, so that data access code is contained within the repository class. I have seen transactions written in a domain driven design book, which work like predicates anyway. A transaction records what you want to achieve and a repository works on that request.


Decide: A 6 Step Behavior Change Methodology that Works! - I've Decided – Our mission is your success!
DECIDE How many times have you set out to achieve a goal, a hope to kick a bad habit, get healthy, be more organized, finish school, or learn something new, only to end up disappointed and unsuccessful. Like most people, you probably find it difficult to stay motivated or find the right resources to help you stay on track. You muster up the motivation to get started, but once an obstacle pops up, life stresses happen, or the excitement wears off, you are back to ground zero.


Retino-A | Avis Cheap-Generic-Retin-A 0 | ООО "Талан"
Now enter your shipping address (in case you have just created your) and pay the amount due. In order to pursue a certificate as a pharmacy technician and pass your exams you may address your inquiry for the Pharmacy Technician Certification Board (PTCB) and also the Institute of Certification of Pharmacy Technicians (ICPT). Experts have demostrated family history doesn't play a big part in developing the disease.
Potatoes and onions are a fantastic source of vitamin B6. Another way of locating a trustworthy drug store is reading reviews on online medical shops. Certain drugs like Coumadin have multiple drug interactions.
Louis University supports the belief in educating the entire person; mind, body, heart, and spirit; which has a strong persistence for ensuring students become leaders with sound ethical and moral values. Or, if need be, they can refer one to your doctor or suggest a medical clinic nearby where you can receive hospital treatment and prescription medication. These online drug dealers bypass government safeguards that want uniformity of quality, a prescription coming from a licensed doctor that says the drug is intended particularly in your case, and that this drug isn't counterfeit, meets manufacturing standards which is safe and effective for the prescribed use.
"(3) The Washington Post(4) commemorated the closing using a write-up that contained just a bit of Schadenfreude. The pharmacist technician must have the prepared prescription, reviewed by way of a pharmacist, before dispensing or submitting the completed order to a patient or customer. The application deadline is within late April, but it is best to apply much sooner.
There are various numbers of online degrees available including associate's, bachelor's and in many cases doctorate programs. With over twenty-five programs to look at, graduate degrees vary from Pharmacy and Health Professionals to Business Administration and Information Technology. Success isn't just good luck: it is really a combination of work, a good credit rating standing, opportunity, readiness and timing.


text:
Quick Guide to Formula 1 Racing: A MensXP Special
Updated on Nov 08, 2012, 09:28 IST
By Pulkit Arora
Come Friday and India will witness speed and adrenaline rush like never before.
The much-anticipated Indian Grand Prix will kick-off tomorrow at Buddha International Circuit in Greater Noida.
Over the last few years, the popularity of F1 racing has touched new skies. And India is no exception. Football, which is often considered as the most popular sport in the world, now faces tough competition from Formula 1. In fact, when it comes to TV viewership, F1 easily beats football as it is the most watched sport in the world. According to some estimates, more than 60 crore people watch F1 daily on some form of media or the other.
First Race, First Track
First F1 race took place at the Silverstone track in Britain in 1950. Prior to this, this was referred to as Grand Prix Motor Racing. When Federation Internationale de l'Automobile drafted new rules (formulae) for racing, the sport came to be known as Formula 1. The first world championship was held in 1958. F1 races are known as Grand Prix preceded by the area in which they are organised.
Special tracks are constructed are F1 races. The track is about 5 to 6 kilometers long and contains many curves (which can be very sharp at times). When a car traverses the track fully, it is said to have complete a lap. A race is normally made up of 55-60 laps. This means a driver has to cover a distance of about 360 kilometers. If a driver drives at an average speed of 320 km/h, it means that he will take about 80 minutes or so to complete the race.
The Game Goes on for Three Days
An F1 Grand Prix is completed in three days. Normally, it starts on Friday and gets over on Sunday. Two free practice sessions are held on Friday. On Saturday morning, another practice race is held. After that, qualifying race is held which determines the starting order of the teams for the main race scheduled to be held on Sunday.
Federation Internationale de l'Automobile (International Federation of Automobiles, FIA) is the topmost organisation for F1 racing. The Formula One Group is a group of companies responsible for the promotion of the FIA Formula One World Championship and exploitation of the sport's commercial rights. The Group is owned ultimately by Delta Topco, a Jersey–based company owned by CVC Capital Partners' funds (approximately 70%) and JPMorgan (approximately 20%). Bernie Ecclestone is the CEO of Formula One Management and Formula One Administration. His family trust owns the remainder apart from small shares held by financial advisers and Ecclestone himself.
Twelve teams compete in an F1 race. Each team has two drivers. This means that a total of 24 drivers take part in the race. There are about 19-20 races in each annual session of the game. In each race, the drivers and his team are rewarded points on the basis of their performance. The driver and the team which have the maximum points at the end of the season are declared champions.
How are the Points Rewarded
There are about 19-20 races in each annual session of the game. This year will see 19 races out of which 16 have already been organised. The Indian Grand Prix (October 28 – October 30) will be the 17th race of the season. The driver which completes all the laps in the least time becomes the winner. After this, a merit list is prepared according to the time taken by all the 24 drivers for completing the laps. It's on the basis of this merit list that the points are awarded. And it's on the basis of these points earned in each race that the champion (team and the driver) is declared at the end of the season.
Before 2010, top 6 drivers+team in a race were awarded points. Then there was a change in the rules. As of now, top 10 drivers+team are considered for points. The drivers finishing at the first, the second and the third spot are awarded 25, 18 and 15 points respectively.
During a race, when a car storms ahead at a speed of 300-320 km/h, a driver has to battle increased temeperature and gravity for about 80 minutes or so. Then there are such turns in the track where gravitational pressure increases five times due to angular velocity. Cockpit, the place where the driver is seated, becomes a hot furnace! The game gives a tremendous rush of adrenaline but there are risks attached. An F1 car gives a mileage of merely 2 kilometers on a litre of high-quality petrol. This means that a car consumers about 150 litres of petrol in one race. The tyres are not inflated with normal air. Nitrogen is used to inflate them so that the tubeless tyres can withstand friction and pressure.
Major Teams for the Present Season
1. Ferrari (Italy)
2. Force India (India)
3. Hispania Racing (Spain)
4. Lotus (Malaysia)
5. McLaren (UK)
6. Mercedes (Germany)
7. Red Bull (Austria)
8. Renault (UK)
9. Sauber (Switzerland)
10. Toro Rosso (Italy)
11. Virgin (Russia)
12. Williams (UK)
Formula 1 Drivers
To become an F1 driver, one needs to obtain a license from FIA. A team can have a maximum of four drivers out of which only two can take part in a race. Drivers have annual salary contracts with the teams. And boy, their paychecks are really, really fat. Their annual salary is more than what Dhoni would earning in five years!! For instance, Ferrari paid an annual salary of 60 million euros to its drivers in the last session. (Special Features, MensXP.com)
Also read: So What Exactly is Siri? and Watch: Best Steve Jobs Videos
Like this article? Follow MensXP on Facebook and Twitter

redpajama_set_name: RedPajamaCommonCrawl


The unfortunate truth about the ANC is that it is a darker shade of the nationalist government mixed with an unhealthy dose of a liberation party based in tribalistic practices. It is a racist government that changes the law instead of its own behavior to the detriment of the population it serves. The ANC is told to scream racism instead of entering into engagement with the groups who have the best interests of South Africa at heart. The result is the enrichment of the ANC cadres and impoverishment of the people they profess to serve. Gross inabilityy to accept that a modicum of sensibility is needed in appointing senior posts have further resulted in serious declines and the racist laws have committed South Africa to a limited pool of skills. BBBEE needs to be repealed urgently if South Africa is to thrive.


NewTek Discussions > LightWave 3D Support > LW - Mac > Lightwave 7.5 not compatible with 10.4?
View Full Version : Lightwave 7.5 not compatible with 10.4?
First off let me say I'm a complete novice to Lightwave, the last time I really used it was version 6.5 in OS9. My main comp now is a G5 running 10.4.7 with Lightwave 7.5d.
I've spent the whole day trying to setup Screamernet II, I followed the old tutorial at Creative Mac (http://www.creativemac.com/2003/05_may/tutorials/screamer030515.htm) to the letter. On an old G4 running 10.3 I can get it to start rendering as a node no problem, however on any G5 machine with 10.4 (including the host machine) as soon as it tries to load a scene the node just crashes.
In the article it mentions having to install Lightwave on each node machine, is that true? It seems to work fine on the G4 machine.
Send me the crash log, and I'll tell you if it's avoidable.


text:
Aleppo Victory… US and its Crime Partners Suffer 'Meltdown of Sanity'
FINIAN CUNNINGHAM | 15.12.2016 | WORLD
The US and its terrorist-sponsoring partners are seeing their criminal regime-change project in ruins, as the Syrian army and its allies win a spectacular victory to retake the strategically important city of Aleppo.
Western governments and their flunkies at the UN are cynically, perversely decrying a «meltdown of humanity».
Closer to the truth is their own «meltdown of sanity». This is because the official Western narrative about the Syrian war is finally being exposed on a glaring scale.
The exposure for the whole world to see is one of a systematic, fake propaganda cover that concealed a criminal enterprise – an enterprise involving terrorist proxies, or fake moderate rebels, whom the Western governments have sponsored for the past six years in a conspiracy to overthrow the government of Syria. The gravity of this systematic crime committed by Washington and its various partners is now unfolding.
Unable to cope with their own cognitive dissonance over the criminality, the Western governments and their complicit corporate news media are resorting to outright denial and to compounding lies with even more lies.
Instead of dealing with the reality that Syrian state forces have recaptured Aleppo from brutal, illegally armed groups, which the West and its regional clients have bankrolled and armed, the West distorts the dramatic victory as the «fall of Aleppo». One report on American channel CNN even referred to the victorious Syrian army and its allies as «persecutors».
With typical unhinged emotion, US ambassador to the UN Samantha Power cited unverified reports of civilians being executed in Aleppo, and slammed Syria and its allies Russia and Iran for having «no shame». It is Power and her Western partners-in-crime, including top UN officials, who should be hanging their heads in shame.
Among the hysterical soundbites about alleged atrocities and slaughter being lobbed around this week was this from UN «humanitarian» official Jens Laerke who said Aleppo was seeing a «meltdown of humanity». Catchy words, but divorced from reality.
Western news media outlets were screaming headlines alleging summary executions of women and children by the Syrian army and its Russian, Iranian and Lebanese allies as they moved in to finally retake the whole of the northern city.
Outgoing UN chief Ban Ki-Moon talked in disparaging tones about an «uncompromising military victory», while his underlings Rupert Colville and Jan Egeland decried «hellish» conditions and «war crimes» committed by Syria and Russia.
The problem is that all these sensational, reckless assertions are based on unverified claims by anonymous «activists» or persons involved with militants – militants who are integrated with terror groups like Jaysh al Fatah, Jabhat al Nusra, Ahrar al Sham and Nour al din al Zenki. All of them affiliated with the internationally proscribed Al Qaeda terrorist network – which the Western governments claim to be at war with.
It truly is a grotesque revelation when Western governments and UN officials publicly spout propaganda on behalf of terrorist groups.
Samantha Power and her British counterpart at the UN Matthew Rycroft cited UN «reports» of 82 civilians being executed, including 11 women and 13 children, by the pro-government Syrian forces during the final hours of recapturing Aleppo. But the same UN «reports» were themselves based on unverified sources supposedly embedded among the terrorists. This is not reportage. It is simply recycling rumors aimed at saving the necks of terrorist groups.
The simple fact of the information coming from unverified sources did not stop the UN, Power, Rycroft and the raft of Western media outlets, including the Washington Post, CNN, Guardian, Independent, France 24 etc, presenting the claims as if they were fact.
Russia's Foreign Minister Sergey Lavrov accused Western governments and their dutiful, unquestioning news media of spreading «fake news» about the dramatic events in Syria this week. Lavrov pointed out that none of the alleged atrocities were acknowledged by independent humanitarian groups.
Syria's ambassador to the UN Bashar al Jaafari also refuted the claims of atrocities that Western counterparts appeared to be so perplexed by.
Western governments and media outlets persisted in their gory fantasies despite abundant video footage that even they themselves were broadcasting which showed thousands of civilians calmly walking away from militant-held pockets of Aleppo towards the Syrian state forces. Is that the behavior of people who are being massacred, summarily executed, slaughtered?
One of the most absurd distortions was this from France 24. The state-owned broadcaster of one of the countries that has supplied weapons and propaganda cover to terrorists in Syria over the past six years described this week how «people in government-held areas of Aleppo were celebrating». Given that the Syrian government holds virtually all of Aleppo that means that the vast majority of Syrians were celebrating. Yet France 24 roils its words to contrive a false division between pro and anti-government populations.
The more logical and truthful depiction is that Syrian civilians are at last able to flee from terror gangs that have held them under siege. But in reporting that the whole false Western narrative about what has been going on in Aleppo and Syria for the past six years would implode like a house of cards.
Why aren't the Western news media interviewing the tens of thousands of civilians who have now managed to flee from the defeated terrorist groups? Why don't the Western media ask questions about the nature of their captivity? Such as, why could they not escape from militant-held eastern Aleppo until now? What do these civilians think of the Syrian army and its allies who have crushed the militants?
The curious, gaping absence of any testimonies carried by the Western media from the thousands of liberated civilians in Aleppo is mirrored by the same curious, gaping absence of testimonies from thousands of civilians liberated elsewhere in Syria by the army over the past year.
That's because those civilians are telling media outlets which are willing to report, such as the Syrian state broadcaster SANA, as well as RT, Press TV and Al Manar, that their nightmare siege imposed by the Western-backed terrorists is over. If Western media outlets were to actually bother to conduct real journalism they would go into liberated areas of Aleppo and other towns and villages across Syria and report that life is returning to happy normalcy for these families and communities.
The truth is Aleppo was invaded by Western-backed mercenaries in July 2012, who turned the eastern side of the city into a den ruled under a reign of terror. A twisted, demented caliphate run by head-chopping Wahhabi jihadists was imposed. Like Syria as a whole, these mercenaries were sanitized in the West as «moderate, pro-democracy rebels» – albeit somehow supposedly «intermingled» with jihadi extremists.
If that were the case, then where are these supposed «moderates» now that the last den of the «rebels» in Aleppo has been routed?
The stark absence of «moderate», «pro-democracy», «Western-value-supporting rebels» emerging from the ruins of Aleppo is as stark as the absence of petrified civilians denouncing Syrian army «atrocities» or Russian «war crimes».
In one resounding moment this week, the Western narrative about Aleppo, and the Syrian war more generally, has collapsed in a pile of dust. No amount of denials and further distortions can hide the exposure of Western lies and propaganda fabrications.
So ironically, Western media outlets have recently whipped up the phenomenon of «fake news» in the context of trying to discredit Russia over alleged electoral interference in the US and Europe.
What Syria has demonstrated is that the real culprits of peddling false news, and more gravely false narratives, are the Western governments and their conceited, self-important news media.
Unable to deal with the unbearable truth of criminal complicity, the official West is displaying a meltdown of sanity.
Aleppo and Syria will one day emerge again from the present ruins. No such recovery from ruins will be made by the ignominious Western governments and their lying, criminally complicit media.
Tags: Al Qaeda Syria US http://www.strategic-culture.org/news/2016/12/15/aleppo-victory-us-its-crime-partners-suffer-meltdown-sanity.html
Posted by eirenae at 1:13 PM No comments:
Aleppo Victory… US and its Crime Partners Suffer '...


text:
namespace SDKTemplate
{
    [Windows::Foundation::Metadata::WebHostHidden]
    public ref class BackgroundActivity sealed
    {
    public:
        void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance);
        void OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason);

        static void OnStart(Windows::ApplicationModel::Background::BackgroundTaskRegistrationGroup^ sender, Windows::ApplicationModel::Activation::BackgroundActivatedEventArgs^ args);
        static void Start(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance);
    private:
        Windows::ApplicationModel::Background::BackgroundTaskCancellationReason CancelReason = Windows::ApplicationModel::Background::BackgroundTaskCancellationReason::Abort;
        volatile bool CancelRequested = false;
        Platform::Agile<Windows::ApplicationModel::Background::BackgroundTaskDeferral> TaskDeferral = nullptr;
        Windows::System::Threading::ThreadPoolTimer^ PeriodicTimer = nullptr;
        unsigned int Progress = 0;
        Windows::ApplicationModel::Background::IBackgroundTaskInstance^ TaskInstance = nullptr;
    };
}


text:
package com.polljoy.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class PJDateHelper {
	public static Date parseDateString(String dateString) {
		// "2014-04-26 09:00:22"
		Date date = null;
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"yyyy-MM-dd hh:mm:ss", Locale.US);
		try {
			date = dateFormat.parse(dateString);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}
}


Roller derby events are a good time for everyone – they're high-energy and kid-friendly, but usually have a nice party atmosphere as well, especially if there's a beer garden.Tickets are inexpensive, and you're pretty much guaranteed a good time.If you really want to unravel the mystery that is a Russian woman, you should probably skip this survival guide entirely and read some Tolstoy and Dostoevsky.Still, since Russian authors were never known for their brevity, sending you off to a library before your first date with Natasha or Tatiana or Olga would simply be inhumane on our part.To the untrained dater it may appear rude or direct but it is a refreshing scene of playing with your cards on the table.Being successful in Dutch dating can require a level of assertiveness: if you want something, just do it.Now, don't be intimidated by the biblical length of the official WFTDA rules (the rule set most roller derby leagues use).Yes, they can be a bit confusing, but you don't have to dive into the minutia right away.
If you're going to be attending a lot of bouts, it's going be much more entertaining if you know the rules." If you're already a player and want to hone your skills, or if this sounds like the right lifestyle for you, read on.


The recent congress of the Republican People's Party saw the re-election of the party's increasingly authoritarian leader, Deniz Baykal. A fixture of the political scene who has stayed at the helm after every election he lost, Baykal epitomizes one of the most serious problems of Turkey's democracy: the dictatorial rule of party chiefs, which prevents both the institutionalization of political parties and healthy policy discussion within them. For this problems to be addressed, both changes in legislation and in political culture will be needed.
Will Clinging to the EU and Atatürk Save the AKP?
Just as it has been faced with the threat of dissolution, the AKP's faith in Europe has been rekindled. More remarkably, the party is even clinging to the Atatürk legacy in an unprecedented way. The AKP's change of heart is testimony to the party's distress. Although displays of "kemalism", in particular, are confusing, the new rhetoric has not convinced analysts that the party's ideological orientation has been altered.
Realizing the rising need for the transportation of the Caspian Basin's energy resources to world markets in the 1990s, Turkish decision-makers claimed that "Turkey should become an energy corridor and an energy hub for producer and consumer countries". All recent governments have to different degrees supported this vision. Turkey's energy hub prospects were boosted by the rapid developments in the Turkish economy, which created an increasing demand for energy resources, and forced the "Energy Strategy" to the focal point of political and bureaucratic circles.
In December 2006, citing Turkey's refusal to extend its customs union to Cyprus, EU Foreign Ministers suspended talks on eight of the thirty-five negotiation chapters in Turkey's accession negotiations. But the importance of Cyprus has been overblown: Cyprus was only the superficial reason for the 'slowdown' decision. Both parties to the accession talks in fact needed to gain time and tend to internal matters. What does the current Turkish turmoil imply for the Cyprus issue and the broader future of Turkey's EU accession negotiations?


text:
\section{Introduction}
Point clouds are unstructured data which is widely used in real-world applications such as autonomous driving. To recognize them using deep neural networks, point clouds can be represented as points \cite{qi2017pointnet}, images \cite{lyu2020learning}, voxels \cite{wu20153d}, or graphs \cite{wang2019dynamic}. Recent works \cite{zhou2020lg, Xiang_2021_ICCV, ma2020efficient, guo2019simple, xiang2019generating, wicker2019robustness, liu2020adversarial} have demonstrated that such deep networks are vulnerable to (gradient-based) adversarial attacks.
Accordingly, several adversarial defenders \cite{zhou2019dup, wu2020if, liu2021pointguard} have been proposed for robust point cloud classification. The basic ideas are often to denoise the (attacked) point clouds before feeding them into the classifiers as input to preserve their prediction accuracy.

\begin{figure}[t]

    \includegraphics[width=1\linewidth]{figures/idea.pdf}
    \vspace{-7mm}
    \caption{Illustration of robust structured declarative classifiers, where our defender is optimized in a structural space.}
    \label{fig:framework}
    \vspace{-4mm}
\end{figure}

\bfsection{Obfuscated gradients}
In the white-box adversarial attacks, the attackers are assumed to have full access to both classifiers and defenders. To defend such attacks, one common way is to {\em break} the gradient over the input data in the backpropagation (either inadvertently or intentionally, \emph{e.g., } a defender is non-differentiable or prevents gradient signal from flowing through the network) so that the attackers fail to be optimized. Such scenarios are called obfuscated gradients. In \cite{athalye2018obfuscated} Athalye \emph{et al. } have discussed the false sense of security in such defenders and proposed new methods, such as Backward Pass Differentiable Approximation (BPDA), to attack them successfully. Take DUP-Net \cite{zhou2019dup} for example, where a non-differentiable Statistical Outlier Removal (SOR) defense strategy was proposed. In \cite{ma2020efficient} Ma \emph{et al. } proposed Joint Gradient Based Attack (JGBA) that can compute the gradient with a linear approximation (an instantiation of BPDA) of the SOR defense to attack DUP-Net successfully.

\bfsection{Implicit gradients}
Now let us consider the scenarios where both defenders and classifiers are differentiable. Then in order to defend the adversarial attacks, one way is to make the calculation of the gradient challenging. To this end, implicit gradients \cite{rajeswaran2019meta} may be more suitable for designing the defenders. {\em An implicit gradient, $\frac{\partial y}{\partial x}$, is defined by a differentiable function $h$ that takes $x, y$ as its input, \emph{i.e., } $\frac{\partial y}{\partial x} = h(x, y)$.} Such an equation can be also considered as a first-order ordinary differential equation (ODE), which is solvable (approximately) using Euler's Method \cite{kag2019rnns}. Here we assume that the gradients through the classifiers
can be easily computed, which often holds empirically. To our best knowledge, so far there is no work on designing adversarial defenders for 3D point clouds based on implicit gradients.

\bfsection{Declarative networks}
Implicit gradients require equations that contain both the input and output of a defender. One potential solution for this is to introduce optimization problems as the defenders, where the first-order optimality conditions provide such equations. In the literature, there have been some works \cite{amos2017optnet, agrawal2019differentiable, lee2019meta, rajeswaran2019meta} that proposed optimization as network layers in deep neural networks. Recently in \cite{gould2021deep} Gould \emph{et al. } generalized these ideas and proposed deep declarative networks. A {\em declarative} network node is introduced where the exact implementation of the forward processing function is not defined; rather the input-output relationship $(x\mapsto \Tilde{x})$ is defined in terms of behavior specified as the solution to an optimization problem $\Tilde{x}\in\argmin_{z\in \mathcal{Z}} f(x,z;\theta)$. Here $f$ is an objective function, $\theta$ denotes the node parameters, and $\mathcal{Z}$ is the feasible solution space. In \cite{gould2021deep} a robust pooling layer was proposed as a declarative node using unconstrained minimization with various penalty functions such as Huber or Welsch, which can be efficiently solved using Newton's method or gradient descent. The effectiveness of such pooling layers was demonstrated for point cloud classification.

\bfsection{Our approach}
Motivated by the methods above, in this paper we propose a novel robust structured declarative classifiers for 3D point clouds by embedding a declarative node into the networks, as illustrated by Fig. \ref{fig:framework}. Different from robust pooling layers in \cite{gould2021deep}, our declarative defender is designed to reconstruct each point cloud in a (learnable) structural space as a means of denoising. To this end, we borrow the idea from structured sparse coding \cite{szlam2012fast, karygianni2014structured, wei2017structured} by representing each point as a linear combination of atoms in a dictionary. Together with the backbone networks, the training of our robust classifiers can lead to a bilevel optimization problem. Considering the inference efficiency, one plausible instantiation of our classifiers, as illustrated in Fig.~\ref{fig:LPC}, is to define the structural space using the permutohedral lattice \cite{adams2010fast, su2018splatnet, gu2019hplflownet}, project each point cloud onto the lattice, generate a 2D image based on the barycentric weights, and feed the image to a 2D convolutional neural network (CNN) for classification. We call this instantiation {\em Lattice Point Classifier (LPC)}.

\begin{figure}[t]

    \centering
    \includegraphics[width=0.9\linewidth]{figures/point_cloud.pdf}
    \vspace{-2mm}
    \caption{Illustration of our Lattice Point Classifier (LPC).
    }
    \label{fig:LPC}
    \vspace{-4mm}
\end{figure}

\bfsection{Our contributions}
We summarize our contributions below:
\begin{itemize}[nosep, leftmargin=*]
    \item We propose a family of novel robust structured declarative classifiers for 3D point clouds where the declarative nodes defend the adversarial attacks through implicit gradients. To the best of our knowledge, we are the {\em first} to explore implicit gradients in robust point cloud classification.

    \item We propose a bilevel optimization framework to learn the network parameters in an end-to-end fashion.

    \item We propose an effective and efficient instantiation of our robust classifiers based on the structured sparse coding in the permutohedral lattice and 2D CNNs.

    \item We demonstrate superior performance of our approach by comparing with the state-of-the-art adversarial defenders under the state-of-the-art adversarial attackers.
\end{itemize}

\section{Related Works}\label{sect:related}
\bfsection{Deep learning for 3D point clouds}
Based on the point cloud representations, we simply group some typical deep networks into four categories. \textit{Point-based networks} \cite{qi2017pointnet, qi2017pointnet++, li2018pointcnn, yan2020pointasnl, wu2019unsupervised} directly take each point cloud as input, extract point-wise features using multi-layer perceptrons (MLPs), and fuse them to generate a feature for the point cloud. \textit{Image-based networks} \cite{su2015multi, qi2016volumetric, yu2018multi, yang2019learning, lyu2020learning, mo2021stereo} often project a 3D point cloud onto a (or multiple) 2D plane to generate a (or multiple) 2D image for further process. \textit{Voxel-based networks} \cite{maturana2015voxnet, wu20153d, riegler2017octnet, wang2017cnn, le2018pointgrid} usually voxelize each point cloud into a volumetric occupancy grid and further some classification techniques such as 3D CNNs are used for the tasks. {\em Graph-based networks} \cite{landrieu2019point, wang2019dynamic, shi2020point, fu2021robust, qian2021pu} often represent each point cloud as a graph such as KNN or adjacency graph which are fed to train graph convolutional networks (GCNs). A nice survey can be found in \cite{guo2020deep}.

\bfsection{Adversarial attacks on point clouds}
Such attacks aim to modify the input point clouds in a way that is not noticeable but can fool a classifier. Attackers can either have a target or not. Targeted attackers try to fool the classifier to predict a specified wrong class, while untargeted ones do not care about the predicted class as long as it is wrong. Nice surveys on adversarial attacks can be found in \cite{ozdag2018adversarial, wang2021adversarial, chakraborty2021survey}. Below we summarize some typical attackers for point clouds:
\begin{itemize}[nosep, leftmargin=*]
    \item {\em Point perturbation \cite{liu2019extending, yang2019adversarial, xiang2019generating, kim2021minimal, ma2020efficient}.} Inspired by Fast Gradient Sign Method (FGSM) \cite{goodfellow2014explaining}, they add on each point a small perturbation constrained by distance metrics (\emph{e.g., } $L_p$ norm \cite{xiang2019generating}, on the surface of an $\epsilon$-ball \cite{liu2019extending}).

    \item {\em Point addition \cite{xiang2019generating, wicker2019robustness, yang2019adversarial}.} Independent point attackers initially pick some points from target classes, add small perturbations and finally append these points to the victim point clouds. Cluster attackers similarly pick most critical points and then find a specified number of small point clusters to append to the victim point clouds. Object attackers attach scaled and rotated foreign object to the original point clouds.

    \item {\em Point dropping.} Adversarial attackers pick critical points from each input point cloud, and drop them to fool the classifier. However, it is a non-differentiable operation. To address the issue in learning, \cite{zheng2019pointcloud} proposed creating saliency maps by viewing dropping a point as moving it to the cloud center. Wicker \emph{et al. } \cite{wicker2019robustness} designed an algorithm to iteratively find the points to drop by minimizing a predefined objective function, similarly in \cite{yang2019adversarial}.

    \item {\em Others.} Hamdi \emph{et al. } \cite{hamdi2020advpc} proposed a transferable adversarial perturbation attacker based on an adversarial loss that can learn the data distribution. Zhao \emph{et al. } \cite{zhao2020isometry} proposed a black-box (\emph{i.e., } no access to the models) attacker with zero loss in isometry, as well as a white-box (\emph{i.e., } full access to the models) attacker based on the spectral norm. LG-GAN \cite{zhou2020lg} is generative adversarial network (GAN) based, which learns and incorporates target features into victim point clouds. A backdoor attacker was proposed in \cite{Xiang_2021_ICCV} to trick the 3D models by inserting adversarial point patterns into the training set so that the victim models learn to recognize the adversarial patterns during inference.
\end{itemize}

\bfsection{Adversarial defense on point clouds}
Adversarial defenses aim to denoise the input point clouds to recover the ground-truth labels from the classifiers. Nice surveys on adversarial defenses can be found in \cite{ozdag2018adversarial, wang2021adversarial, chakraborty2021survey}. Below we summarize some typical defenders for point clouds:
\begin{itemize}[nosep, leftmargin=*]
    \item {\em Statistical outlier removal (SOR) \cite{rusu2008towards}.} SOR can be used to remove local roughness on the (smooth) surface as a means of defense. SOR is not differentiable, producing obfuscated gradients for defenders. DUP-Net \cite{zhou2019dup} uses SOR and an upsampling network to reconstruct higher resolution point clouds. Similarly, IF-Defense \cite{wu2020if} utilizes SOR, followed by a geometry-aware model to encourage evenly distributed points. However, such defenders have been demonstrated to be attackable in \cite{tsai2020robust, ma2020efficient}. Dong \emph{et al. } \cite{dong2020self} proposed replacing SOR by attention mechanism.

    \item {\em Random sampling.} Yang \emph{et al. } \cite{yang2019adversarial} suggested that 3D models with random sampling are robust to adversarial attacks. PointGuard \cite{liu2021pointguard} proposed majority voting for point cloud classification by predicting multiple randomly subsampled point clouds.

    \item {\em Data augmentation.} Tramer \emph{et al. } \cite{tramer2017ensemble} demonstrated that data augmentation can effectively account for adversarial attacks. Tu \emph{et al. } \cite{tu2020physically} proposed generating physically realizable adversarial examples to train robust Lidar object detectors. Zhang \emph{et al. } \cite{zhang2021art} proposed randomly permuting training data as a simple data augmentation strategy. PointCutMix \cite{zhang2021pointcutmix} pairs two training clouds and swaps some points between the pair to generate new training data.
\end{itemize}

\bfsection{Permutohedral lattice}
Permutohedral lattice is a powerful operation to project the coordinates from a high dimensional space onto a hyperplane that defines the lattice. It has been widely used in high dimensional filtering \cite{adams2010fast, jampani2016learning} that consists of three components, \emph{i.e., } splat, blur and slice. In particular, we illustrate the splat in Fig. \ref{fig:LPC}, where each square represents a projection (\emph{i.e., } projected point) from a 3D coordinate. The splat first locates the enclosing lattice simplex for the 3D point and calculates the vertex coordinates of the simplex. Then each projection distributes its value to the vertices using barycentric interpolation with barycentric weights that are calculated as the normalized triangular areas between the projection and any pair of its corresponding lattice vertices.
We refer the readers to \cite{adams2010fast} for more details. Recently permutohedral lattice has been successfully explored in point cloud segmentation \cite{su2018splatnet, gu2019hplflownet, rosu2021latticenet} with remarkable performance.

\section{Robust Structured Declarative Classifiers}
\subsection{Structured Declarative Defender}
Recall that adversarial defenders often aim to denoise the input point clouds by reconstructing them in certain ways, and sparse coding \cite{zhang2015survey} is one of the classic approaches for finding a sparse representation of the input data in the form of a linear combination of basic elements as well as those basic elements themselves. Due to its simplicity, we consider using sparse coding as a means to construct declarative nodes.

Specifically, in the 3D space given a (learnable) dictionary $\mathbf{B}\in\mathbb{R}^{3\times N}$ with $N\gg 3$ atoms, (structured) sparse coding aims to solve the following optimization problem for each point $\mathbf{x}_i\in\mathbb{R}^3$ in a point cloud $\mathbf{x}=\{\mathbf{x}_i\}\subseteq\mathbb{R}^3$:
\begin{align}\label{eqn:sc}
    \Tilde{\mathbf{x}}_i \in \argmin_{\mathbf{z}\in\mathcal{Z}} f(\mathbf{x}_i, \mathbf{z}) = \frac{1}{2}\|\mathbf{x}_i - \mathbf{B}\mathbf{z}\|^2 + \phi(\mathbf{z}),
\end{align}
where $\phi$ denotes a regularization term, and $\mathcal{Z}\subseteq\mathbb{R}^N$ denotes a structural feasible solution space.

\bfsection{Obfuscated \& implicit gradients in $\frac{\partial \Tilde{\mathbf{x}}_i}{\partial \mathbf{x}_i} = \frac{\partial \mathbf{z}}{\partial \mathbf{x}_i}\Big|_{\mathbf{z}=\Tilde{\mathbf{x}}_i}$}
To see this, we can rewrite Eq.~\eqref{eqn:sc} as $\Tilde{\mathbf{x}}_i \in \argmin_{\mathbf{z}} F(\mathbf{x}_i, \mathbf{z}) = f(\mathbf{x}_i, \mathbf{z}) + \phi(\mathbf{z}) + \delta(\mathbf{z})$, where $\delta(\mathbf{z})$ denotes the Dirac delta function returning 0 if $\mathbf{z}\in\mathcal{Z}$ holds, otherwise, $+\infty$. Therefore, $F$ will become non-differentiable when $\mathbf{z}\notin\mathcal{Z}$ or $\phi$ is non-differentiable over $\mathbf{z}\in\mathcal{Z}$, leading to obfuscated gradients. Otherwise, based on the first-order optimality condition, we have
$\mathbf{B}^T\mathbf{B}\Tilde{\mathbf{x}}_i - \mathbf{B}^T\mathbf{x}_i + \phi'(\Tilde{\mathbf{x}}_i) = \mathbf{0}$, where $(\cdot)^T$ denotes the matrix transpose operator and $\phi'$ denotes the first-order derivative of $\phi$. By taking another derivative on both sides, we then have a linear system $\left(\mathbf{B}^T\mathbf{B}+\phi''(\Tilde{\mathbf{x}}_i)\right)\cdot\frac{\partial \Tilde{\mathbf{x}}_i}{\partial \mathbf{x}_i} = \mathbf{B}^T$, if the second-order derivative, $\phi''$, exists at $\mathbf{z}\in\mathcal{Z}$. Clearly, solving this linear system may be challenging, because $\phi''(\Tilde{\mathbf{x}}_i)$ may not be computable and the matrix $\mathbf{B}^T\mathbf{B}+\phi''(\Tilde{\mathbf{x}}_i)$ may be rank-deficient. Such phenomenons lead to implicit gradients.

\subsection{Parameter Learning via Bilevel Optimization}
Fig. \ref{fig:framework} illustrates our approach with two components, \emph{i.e., } a declarative defender $f$ and a network backbone $g$ that takes the outputs of the defender as input and then makes predictions. Equivalently we can formulate the training of such networks as a bilevel optimization problem as follows:
\begin{align}
    & \min_{\mathbf{B}, \omega} \sum_{(\mathbf{x}, y)\in\mathcal{X}\times\mathcal{Y}} \ell\Big(g(\Tilde{\mathbf{x}}; \omega), y\Big), \\
    & \mbox{s.t.} \,
    \Tilde{\mathbf{x}}_i \in \argmin_{\mathbf{z}\in\mathcal{Z}}\frac{1}{2}\|\mathbf{x}_i - \mathbf{B}\mathbf{z}\|^2 + \phi(\mathbf{z}), \forall \mathbf{x}_i\in\mathbf{x}, \nonumber
\end{align}
where $(\mathbf{x}, y)\in\mathcal{X}\times\mathcal{Y}$ denotes a training sample with data $\mathbf{x}$ and label $y$, $\ell$ denotes a loss function such as cross-entropy, and $\mathbf{B}, \omega$ denote the defender and network parameters, respectively. Same as training deep networks, we can solve this optimization problem using (stochastic) gradient descent.

\bfsection{Validity of $\frac{\partial g}{\partial \Tilde{\mathbf{x}}_i} = \frac{\partial g}{\partial \mathbf{z}}\Big|_{\mathbf{z}=\Tilde{\mathbf{x}}_i}$ in the structural space}
In a gradient based adversarial attack, the gradient for modifying an input point $\mathbf{x}_i$ through backpropagation can be written as $\frac{\partial g}{\partial \Tilde{\mathbf{x}}_i}\frac{\partial \Tilde{\mathbf{x}}_i}{\partial \mathbf{x}_i}$. Assuming that $\frac{\partial \Tilde{\mathbf{x}}_i}{\partial \mathbf{x}_i}$ can be computed exactly, then the gradient in the attack would hold in general only if $\mathbf{z}$ was unconstrained so that $\frac{\partial g}{\partial \Tilde{\mathbf{x}}_i}$ is valid. Unfortunately in our case this is not true as we constrain $\mathbf{z}\in\mathcal{Z}$. Therefore, the attack in the declarative node will produce inaccurate gradients, and such errors will be propagated to the adversarial examples, leading to failure cases together with $\frac{\partial \Tilde{\mathbf{x}}_i}{\partial \mathbf{x}_i}$.

\subsection{Instantiation: Lattice Point Classifier}
So far we have explained the learning principles and defense philosophy in our approach. The key challenge now is how to design the structural space $\mathcal{Z}$ and the regularizer $\phi$ to achieve robust point cloud classifiers that can be trained and inferred effectively and efficiently. To address this issue, we borrow the idea from permutohedral lattice, and propose an instantiation, namely, Lattice Point Classifier (LPC).

\setlength{\intextsep}{0pt}%
\setlength{\columnsep}{10pt}%
\begin{wrapfigure}{r}{.4\linewidth}

	\begin{minipage}[b]{\linewidth}
		\begin{center}
			\centerline{\includegraphics[width=\linewidth]{figures/bw.pdf}}
		\end{center}
	\end{minipage}
	\vspace{-11mm}
    \caption{Illustration of barycentric coordinates and weights.}
    \label{fig:bw}

\end{wrapfigure}

\bfsection{Geometric view on barycentric coordinates and their weights}
Barycentric coordinates ($\overrightarrow{A}$, $\overrightarrow{B}$, $\overrightarrow{C}$ in Fig. \ref{fig:bw}) can be used to express the position of any point ($\overrightarrow{P}$) located on the entire triangle with three scalar weights ($\alpha, \beta, \gamma$). To compute $\overrightarrow{P}$ using barycentric coordinates we can always use the following equation:
\begin{align}\label{eqn:P}
    \overrightarrow{P} = \alpha \overrightarrow{A} + \beta \overrightarrow{B} + \gamma \overrightarrow{C}, \, \exists \alpha, \beta, \gamma \geq 0, \alpha+\beta+\gamma = 1.
\end{align}
Note that this equation holds for an arbitrary dimensional space, including the 3D space. Now given $\overrightarrow{A}, \overrightarrow{B}, \overrightarrow{C}, \overrightarrow{P}$, we can compute $\alpha, \beta, \alpha$ using the normalized areas. Taking $\gamma$ for example, we can compute it as follows:
\begin{align}
    \gamma = \frac{\|\overrightarrow{AB}\times\overrightarrow{AP}\|}{\|\overrightarrow{AB}\times\overrightarrow{AC}\|} \propto \|\overrightarrow{AB}\times\overrightarrow{AP}\|,
\end{align}
where $\overrightarrow{AB}=\overrightarrow{B} - \overrightarrow{A}, \overrightarrow{AP}=\overrightarrow{P} - \overrightarrow{A}, \overrightarrow{AC}=\overrightarrow{C} - \overrightarrow{A}$, $\times$ denotes the cross product operator, and $\|\cdot\|$ denotes the $\ell_2$ norm of a vector measuring its length. Clearly, the barycentric weights define a nonlinear mapping that can be computed efficiently using the splat operation for the permutohedral lattice.

\bfsection{Constructing $\mathcal{Z}$ and $\phi$ using barycentric weights}
By substituting Eq. \eqref{eqn:P} into Eq. \eqref{eqn:sc}, we manage to define a structured sparse coding problem, where the structural space $\mathcal{Z}$ and the regularizer $\phi$ can be constructed as follows:
\begin{align}
    &\mathcal{Z}\stackrel{def}{=}\left\{\mathbf{z} \mid \mathbf{z}^T\mathbf{e} = 1, \mathbf{z} \succeq \mathbf{0} \right\}, \\ &\phi(\mathbf{z})\stackrel{def}{=} \lambda\sum_{n=1}^N \|\mathbf{B}\mathbf{z} - \mathbf{B}_n\|\cdot 1_{\{\mathbf{z}_n>0\}},
\end{align}
where $\mathbf{e}$ denotes a vector of 1's, $\succeq$ denotes the entry-wise operator of $\geq$, $\mathbf{B}_n\in\mathbb{R}^3$ denotes the $n$-th column in $\mathbf{B}$, $1_{\{\cdot\}}$ denotes a binary indicator returning 1 if the condition holds, otherwise 0 (\emph{i.e., } the {\em binarization} of barycentric weights), and $\lambda\geq0$ is a small constant controlling the contribution of $\phi$ to the objective so that it will not be dominated by $\phi$.

\begin{prop}\label{prop:1}
Supposing that $\mathbf{B}$ in Eq. \eqref{eqn:sc} represents the vertices in a permutohedral lattice that is large enough to cover all possible projections from points among the data, then there exists a solution to minimize the reconstruction loss using three vertices, at most, and the minimum loss is equal to the projection loss onto the lattice.
\end{prop}
This is because Eq. \eqref{eqn:P} defines a lossless representation using a linear combination of three vertices. The only loss occurs when projecting a point to the permutohedral lattice.

\setlength{\intextsep}{0pt}%
\setlength{\columnsep}{10pt}%
\begin{wrapfigure}{r}{.4\linewidth}

	\begin{minipage}[b]{\linewidth}
		\begin{center}
			\centerline{\includegraphics[width=\linewidth]{figures/defense.pdf}}
		\end{center}
	\end{minipage}
	\vspace{-7mm}
    \caption{Illustration of our defense mechanism.}
    \label{fig:defense}

\end{wrapfigure}
\bfsection{Defense mechanism in LPC}
Fig. \ref{fig:defense} illustrates how our declarative defender works with the permutohedral lattice, where the triangle, circles and squares represent a lattice cell, 3D points and their projections on the cell, respectively. In the adversarial point cloud, the attacker modifies a point from $\mathbf{x}_i$ to $\mathbf{x}_i'$. Then during the inference, our defender projects $\mathbf{x}_i'$ to $\Tilde{\mathbf{x}}_i'$ on the lattice.

\begin{prop}
Supposing $\Tilde{\mathbf{x}}_i = \alpha \overrightarrow{A} + \beta \overrightarrow{B} + \gamma \overrightarrow{C}$ where $\alpha, \beta, \gamma$ are the barycentric weights, then in order to guarantee that $\Tilde{\mathbf{x}}_i, \Tilde{\mathbf{x}}_i'$ lie in different cells, the distance between $\mathbf{x}_i$ and $\mathbf{x}_i'$ should be bigger than the shortest distance between $\Tilde{\mathbf{x}}_i'$ and the boundary of the triangle, that is:
\begin{align}
    \|\mathbf{x}_i - \mathbf{x}_i'\| > \min\left\{\frac{\alpha}{\|\overrightarrow{BC}\|}, \frac{\beta}{\|\overrightarrow{AC}\|}, \frac{\gamma}{\|\overrightarrow{AB}\|}\right\}\cdot s,
\end{align}
where $s$ denotes the area of the triangle. In particular, if the triangle is equilateral, then $\|\mathbf{x}_i - \mathbf{x}_i'\| > \frac{\sqrt3}{2}l\cdot\min\{\alpha, \beta, \gamma\}$ where $l$ denotes the side length.
\end{prop}
It will be more intuitive to understand this result if we binarize the barycentric weights before feeding them into the backbone network for classification, because different projections lying in the same lattice cell will lead to the same representation. This could be an effective way to remove the adversarial noise in the data. Also, this result indicates that (1) the points whose projections are closer to the boundary are easier to change their sparse representations, (2) the movements that make such changes are proportional to the scale of the lattice cell. In general, larger cells will be more tolerant to the adversarial noise, but they may sacrifice the generalization of the classifiers.

\begin{figure}[t]
    \centering
    \includegraphics[width=0.9\linewidth]{figures/pc_2d_pld.png}
    \vspace{-3mm}
    \caption{Illustration of {\bf (left)} a point cloud, {\bf (middle)} its lattice representation, {\bf (right)} its image for classification.}
    \label{fig:image}
  	\vspace{-4mm}
\end{figure}

\bfsection{Workflow of LPC}
To summarize, it is operated as follows:
\begin{enumerate}[nosep, leftmargin=*]
    \item Given a point cloud, the barycentric weights of each point are computed using the splat for permutohedral lattice;

    \item Generate an image for the point cloud by averaging the barycentric weights over all the points (after binarization if applied) and aligning the lattice with the image representation (see Fig. \ref{fig:image} for illustration);

    \item Apply a 2D CNN as the backbone network to classify the image produced by the point cloud.
\end{enumerate}

\bfsection{Implementation}
The key challenge in our implementation of LPC is how to determine the projection matrix for the hyperplane and the scale of each permutohedral lattice cell.
\begin{itemize}[nosep, leftmargin=*]
    \item {\em Projection matrix:} By referring to \cite{adams2010fast}, we initialize the projection matrix as $\footnotesize \begin{bmatrix}
2  & -1 & -1\\
-1 &  2 & -1\\
-1 & -1 &  2\\
\end{bmatrix}$ and train the network in an end-to-end fashion. However, we observe that a big update of this matrix will make the training crash, and to avoid this issue, the update per iteration has to be tiny, leading to almost unnoticeable change eventually. The reason for this phenomenon is that this matrix has to satisfy certain requirements (see \cite{adams2010fast}), and thus the unconstrained update in backpropagation cannot work here. Therefore, in our experiments we initialize and fix the projection matrix. We refer to \cite{gu2019hplflownet} for the lattice transformation.

    \item {\em Scale of lattice cell:} The parameter is simply not differentiable in backpropagation, and thus we tune it as a predefined hyper-parameter using cross-validation with grid search, same for the other hyper-parameters such as learning rate. Such scales have a significant impact on the image resolution used in 2D CNNs for classification.
\end{itemize}

Specifically, we evaluate our LPC comprehensively based on three different CNNs, \emph{i.e., } VGG16 \cite{simonyan2014very}, ResNet50 \cite{he2016deep}, and EfficientNet-B5 \cite{tan2019efficientnet} as the backbone network with randomly initialization. By default, the image resolution for each backbone network is $512\times512$, $128\times128$ and $456\times456$, respectively. On ModelNet40 \cite{wu20153d} we train the three models using a learning rate of $10^{-4}$, but on ScanNet \cite{dai2017scannet} we only train our best model, \emph{i.e., } EfficientNet-B5, using a learning rate of $5\times10^{-5}$. We use Adam \cite{kingma2014adam} as our optimizer in all of our experiments with weight decay of $10^{-4}$ and learning rate decay of 0.7 for every 20 epochs. Dropout \cite{srivastava2014dropout} and data augmentation are applied as well when needed.

\section{Experiments}

\bfsection{Datasets}
We conduct our experiments on ModelNet40 \cite{wu20153d} and ScanNet \cite{dai2017scannet}. ModelNet40 has a collection of 12,311 3D CAD objects from 40 common categories. It is split into 9,843 training and 2,468 test samples. Following \cite{qi2017pointnet, xiang2019generating}, we uniformly sample 1,024 points from the surface of the original point cloud per object and scale them into a unit ball. ScanNet contains 1,513 RGB-D scans from over 707 real indoor scenes with 2.5 million views. Following \cite{li2018pointcnn}, we generate 12,445 training and 3,528 test point clouds from 17 categories, with 1,024 points for each point cloud as well.

\begin{figure}[t]

	\begin{minipage}[b]{0.495\linewidth}
		\begin{center}
			\centerline{\includegraphics[width=1.05\linewidth, keepaspectratio,]{figures/loss_model1.png}}
			\vspace{-1mm}
			\centerline{(a) ModelNet40}
		\end{center}
	\end{minipage}
	\hfill
	\begin{minipage}[b]{0.495\linewidth}
		\begin{center}
			\centerline{\includegraphics[width=1.01\linewidth,keepaspectratio]{figures/loss_scan1.png}}
			\vspace{-1mm}
			\centerline{(b) ScanNet}
		\end{center}
	\end{minipage}

	\vspace{-5mm}
    \caption{Training loss comparison on both datasets using EfficientNet-B5 as the backbone.}
    \label{fig:benchmark}
	\vspace{-4mm}
\end{figure}

\bfsection{Baselines}
We compare our Lattice Point Classifier (LPC) with different adversarial defenders for point clouds that work with PointNet \cite{qi2017pointnet}, including DUP-Net \cite{zhou2019dup} (with SOR and the upsampling network), IF-Defense \cite{wu2020if} (with ConvONet \cite{peng2020convolutional}), and robust pooling layer (RPL) \cite{gould2021deep}. We utilize public code \cite{xu2019pnetimp} to train PointNet using the default setting and evaluate DUP-Net and IF-Defense based on the implementation in \cite{wu2020if}. We report the best performance for each defender after fine-tuning. Specifically, we set $k=2$ (the number of neighbor points) in KNN and $\alpha=1.1$ (the percentage of outliers) for SOR, use 2 for the upsampling rate in DUP-Net, and choose the Welsch penalty function \cite{dennis1978techniques} for RPL \cite{gould2021deep} to replace the max pooling layer in PointNet. The model with RPL is trained with adversarial point clouds where 10\% of input points are replaced by random outliers.

\bfsection{Adversarial attackers}
Eight attackers are utilized to evaluate the robustness of different point cloud classifiers, including untargeted attackers (FGSM \cite{goodfellow2014explaining} and JGBA \cite{ma2020efficient}), targeted attackers (perturbation, add, cluster and object attackers \cite{xiang2019generating}), isometry transformation based attackers \cite{zhao2020isometry} (the untargeted black-box TSI attack and the targeted white-box CTRI attack), and GAN based LG-GAN attacker \cite{zhou2020lg}.

We apply both FGSM and JGBA to the full test set of both datasets. We slightly modify FGSM for attacking DUP-Net and IF-Defense under the white-box setting as both defenders are non-differentiable. To do so, during an attack we simulate the SOR process and obtain the indices of the remaining points based on which the gradient is passed to the remaining points. By default, the parameter $\epsilon$ in FGSM is set to 0.1, and the perturbation norm constraint $\epsilon$, number of iterations $n$ and step size $\alpha$ in JGBA are set to 0.1, 40, 0.01, respectively. Such parameters work well in practice.

For the targeted attackers, by following \cite{xiang2019generating} we pick 10 large classes from ModelNet40, where a batch of 6 point clouds per class is randomly selected and attacked using the other 9 classes as the targets, leading to $10 \times 9 \times 6 = 540$ victim-target pairs. Similarly, from ScanNet we randomly select a batch of 6 point clouds as well from the 7 classes that contain more than 100 point clouds in test data. The learning rate of all the targeted attackers is set to 0.01. For DUP-Net and IF-Defense, we first attack clean PointNet to obtain adversarial point clouds, and then feed them into DUP-Net and IF-Defense for prediction. The perturbation attack first introduces small random perturbations on all original points, and uses $L_2$ norm to constrain the adversarial shifts.
Using the add attacker, we add 60 points to each cloud and use Chamfer distance as the metric. Cluster and object attackers generate the initial clusters with parameter $\epsilon=0.11$ in DBSCAN \cite{ester1996density}.
Using the cluster attacker, we add 3 clusters of 32 points to the original clouds. Using the object attacker, three 64-point adversarial objects are attached to each original point cloud.

For the TSI/CTRI attacker in \cite{zhao2020isometry}, we evaluate the performance of LPC on ModelNet40 using EfficientNet-B5. By following \cite{zhao2020isometry} we use this attacker with the default settings to attack 2,000 randomly selected point clouds. The attacker applies the black-box TSI attacker first to trick the models, and then the white-box CTRI attacker if TSI fails.

We implemented a vanilla version of LPC in TensorFlow with binarized weights, ResNet50 as the backbone and $128\times128$ as the 2D image size. On ModelNet40, we trained a TensorFlow LPC model and integrated it into LG-GAN to generate adversarial samples. For the benchmark models, we trained a TensorFlow PointNet \cite{qi2017pointnet} model and generates adversarial samples with it since all other benchmark defenses are PointNet based. We followed the setups in \cite{zhou2020lg} and set weight factor $\alpha=100$.

\begin{table}
\setlength{\tabcolsep}{1pt}
\centering
\caption{Our learning choice comparison in terms of test accuracy (\%) with learning rate $10^{-4}$.}
\vspace{-3mm}
\begin{tabular}{  c | c  c  c  c  c  c }

    \toprule
    T-Net \cite{qi2017pointnet}           &      & \checkmark & & & \checkmark &            \\
    Binarized weights      &      &            & \checkmark &  & \checkmark & \checkmark \\
    Random rotation   &      &            &            &      \checkmark        &            & \checkmark   \\
    \midrule
    {\small ResNet-50 on ModelNet40}     & 88.2 &       87.3 &       \textbf{88.9} & 60.0 & 88.2  & 75.2 \\
    \midrule
    {\small EfficientNet-B5 on ModelNet40}     & - &       - &       \textbf{89.5} & 83.3 & - & 84.8 \\
    \midrule
    {\small EfficientNet-B5 on ScanNet}     & 80.5 &       - &      80.0 & {\bf 82.6} & - & - \\
\bottomrule
\end{tabular}
\label{table:cls_module}
\vspace{-2mm}
\end{table}

\begin{table}
\centering
\setlength{\tabcolsep}{4pt}
\caption{Inference Time (ms) on an NVIDIA V100S GPU with batch size 1 (clean PointNet \cite{qi2017pointnet} takes 8.6 ms)}
\vspace{-2mm}
\begin{tabular}{  c  c  c | c  c  c}
    \toprule
     \thead{DUP-Net\\\cite{zhou2019dup}} & \thead{IF-Defense\\\cite{wu2020if}}
     & \thead{RPL\\\cite{gould2021deep}} & \thead{LPC w/\\VGG} & \thead{LPC w/\\ResNet} &  \thead{LPC w/\\EfficientNet} \\
    \midrule
	 808.1   &  1793.6 & 62.0 & 21.4 & 25.1 & 59.0 \\
    \bottomrule

\end{tabular}
\label{table:run_time}
\vspace{-3mm}
\end{table}

\begin{table*}[t]
\centering
\caption{Test accuracy (\%) comparison (higher is better) on the full test datasets, where ``-'' indicates no result.} \vspace{-3mm}
\begin{tabular}{  cc | c | ccc | ccc  }
    \toprule
         & & PointNet & \thead{PointNet w/\\DUP-Net \cite{zhou2019dup}} & \thead{PointNet w/\\IF-Defense \cite{wu2020if}} & \thead{PointNet w/\\ RPL \cite{gould2021deep}} & \thead{LPC w/\\ VGG16} & \thead{LPC w/\\ ResNet50} & \thead{LPC w/\\EfficientNet}  \\
    \hline
	\hline
	\multirow{3}{*}{ModelNet40} & No attack
	& \({\bf 90.15}\) & \(89.30\) & \(87.60\) &  \(84.76\) & \(88.65\) & \(88.90\) & \(89.51\)  \\
    & FGSM \cite{goodfellow2014explaining}
	& \(45.99\) & \(61.63\) &  \(38.75\)&   \(0.04\) & \(88.65\) & \(88.90\) & \({\bf 89.51}\)   \\
    & JGBA \cite{ma2020efficient}
	&  \(0.00\) &  \(1.14\) &  \(5.37\) &   \(0.00\) & \(88.65\) & \(88.90\) & \({\bf 89.51}\)   \\
	\hline
	\hline
	\multirow{3}{*}{ScanNet} & No attack
	& \({\bf 84.61}\) & \(83.62\) & \(80.19\) &  \(76.02\) & - & - & \(83.16\)   \\
    & FGSM \cite{goodfellow2014explaining}
	& \(45.66\) & \(73.67\) & \(71.14\) &   \(1.70\) &  - & - & \({\bf 83.16}\)    \\
    & JGBA \cite{ma2020efficient}
	&  \(0.00\) &  \(7.77\) & \(13.45\) &   \(0.00\) &  - & - & \({\bf 83.16}\)    \\
	\bottomrule

\end{tabular}
\label{table:attack_accu}
\end{table*}

\begin{table*}[t]
\centering
\caption{Attack success rate (\%) comparison (lower is better), where ``-'' indicates no result. The standard deviations of our LPC range from 0\% to 0.28\% in success rate on ModelNet40.}\vspace{-3mm}
\begin{tabular}{ c c | c | c  c  c | c  c  c  }
    \toprule
         & & PointNet & \thead{PointNet w/\\DUP-Net \cite{zhou2019dup}} & \thead{PointNet w/\\IF-Defense \cite{wu2020if}} & \thead{PointNet w/\\ RPL \cite{gould2021deep}} & \thead{LPC w/\\ VGG16} & \thead{LPC w/\\ ResNet50} & \thead{LPC w/\\EfficientNet}  \\
    \hline
    \hline
    \multirow{6}{*}{ModelNet40} & FGSM \cite{goodfellow2014explaining}
	& \(48.99\) & \(30.77\) &  \(55.78\)&  \(99.95\)&  \({\bf 0.00}\) &  \({\bf 0.00}\) &  \({\bf 0.00}\)   \\
    & JGBA \cite{ma2020efficient}
	& \(100.00\)& \(98.73\) &  \(93.85\) & \(100.00\)&  \({\bf 0.00}\) &  \({\bf 0.00}\) &  \({\bf 0.00}\)   \\
	& Perturbation \cite{xiang2019generating}
	& \(100.00\)&  \({\bf 0.095}\) &  \({\bf 0.095}\) &  \(3.95\) &  \(0.56\) &  \(0.37\) &  \(0.38\)   \\
	& Add \cite{xiang2019generating}
	& \(99.72\) &  \({\bf 0.095}\) &  \({\bf 0.095}\) &  \(3.33\) &  \(0.56\) &  \(0.19\) &  \(0.19\)   \\
	& Cluster \cite{xiang2019generating}
	& \(98.34\) &  \(6.76\) &  \(6.30 \) & \(17.04\) &  \(1.11\) &  \({\bf 0.93}\) &  \(1.21 \)   \\
	& Object \cite{xiang2019generating}
	& \(98.43 \) &  \(1.02\) &  \(1.11\) & \(74.07\) &  \(0.93\) &  \(1.11\) &  \({\bf 0.75} \)   \\
	\hline
	\hline
	\multirow{6}{*}{ScanNet} & FGSM \cite{goodfellow2014explaining}
	& \(46.03\) & \(10.29\) & \(11.28\) &  \(97.76\)& - & - & \({\bf 0.00}\)    \\
    & JGBA \cite{ma2020efficient}
	& \(100.00\)& \(90.55\) & \(83.21\) & \(100.00\)& - & - & \({\bf 0.00}\)    \\
	& Perturbation \cite{xiang2019generating}
	& \(100.00\)&  \(3.17\) &  \({\bf 2.38}\) &  \(3.03\) & - & - & \(12.70\)    \\
	& Add \cite{xiang2019generating}
	& \(100.00\)&  \({\bf 1.98}\) &  \(2.38\) & \(18.65\) & - & - & \(2.78\)    \\
	& Cluster \cite{xiang2019generating}
	& \(100.00\)&  \(30.16\)&  \(23.81\)&  \(40.87\) & - & - & \({\bf 9.92}\)    \\
	& Object \cite{xiang2019generating}
	& \(100.00\)&  \(7.14\) &  \(7.54\) &  \(85.71\) & - & - & \({\bf 5.95}\)    \\
    \bottomrule

\end{tabular}
\label{table:attack_main}
\vspace{-4mm}
\end{table*}

\begin{table}
\centering
\setlength{\tabcolsep}{5pt}
\caption{Performance comparisons under LG-GAN \cite{zhou2020lg} attacks. Attack success rate (Succ., \%) on different models and their classification accuracy (Accu., \%) under attack}
\vspace{-2mm}
\begin{tabular}{ c | c | c  c  c | c }
    \toprule
      & \thead{PointNet\\\cite{qi2017pointnet}} & \thead{DUP-Net\\\cite{zhou2019dup}} & \thead{IF-Defense\\\cite{wu2020if}}
     & \thead{RPL\\\cite{gould2021deep}} & \thead{LPC w/\\ResNet} \\
    \midrule
	 Accu. & 0.6  &  31.6 & 37.2 & 56.8 & {\bf76.7}  \\
	 Succ. & 97.0 &  13.9 & 10.4 &  2.6 &  {\bf0.8}  \\
    \bottomrule

\end{tabular}
\vspace{-1mm}
\label{table:lggan_attack}
\end{table}

\subsection{Ablation Study}
\bfsection{Learning choices}
In Table \ref{table:cls_module} we list three learning choices that we would like to evaluate for improving the performance of vanilla LPC, \emph{i.e., } T-Net used in PointNet, binarized barycentric weights, and random rotation in data augmentation (together with point cloud random shifting and dropping \cite{qi2017pointnet}). We can see that: (1) T-Net seems to deteriorate the performance always. (2) Binarized weights work better on ModelNet40 than ScanNet, but compared with using barycentric weights the difference is <1\%. (3) Random rotation improves the performance on ScanNet, but worsens it on ModelNet40. This phenomenon can be partially explained from the training loss curves as shown in Fig. \ref{fig:benchmark}, where on ScanNet the overfitting occurs clearly without random rotation while on ModelNet40 random rotation makes the convergence slower and unstable.

\bfsection{Running time}
Overall LPC achieves the fastest inference speed among all competing defenses as shown in Table \ref{table:run_time}. Our deepest model (17fps) is over 13 times faster than SOR based defenses. We can also improve the running time using shallower networks such as VGG16 (45fps) by slightly sacrificing the performance. We also tested the running time for each key component (declarative node and backbone 2D networks). With EfficientNet-B5 as the backbone, the declarative node and 2D network take $17.1$ and $41.9$ ms respectively during inference, and $15.5$ and $165.3$ ms during backpropagation. Clearly, the gradient passing through the declarative node takes relatively constant time in both feedforward and backpropagation. Considering the depth of EfficientNet-B5, the time spent on the declarative node is actually pretty long (recall that there is no learnable parameter inside), especially during inference. This partially validates our intuition of defending the adversarial attacks using implicit gradients.

\subsection{State-of-the-art Performance Comparison} \label{sect:cls_res}
We measure the robustness of classifiers using two metrics, \emph{i.e., } classification accuracy, and attack success rate. Classification accuracy under attacks is measured by feeding the entire adversarial attacked test set to the victim models. It is only calculated for untargeted attackers. The attack success rate is the ratio between the number of successful attacks to the number of all attempt attacks. For untargeted attacks, tricking the model to predict a wrong class is considered a success, while for targeted attacks it will have to trick the victim model to a specific class to be considered as successful. Untargeted attackers will only attack the point clouds that are correctly classified by the victim models, and targeted attackers will attack victim-target pairs.

\subsubsection{Classification Accuracy}
We summarize our comparison in Table \ref{table:attack_accu}. On ScanNet, we only show the performance of LPC with EfficientNet-B5, because it achieves the best accuracy on ModelNet40. We can see that: (1) On the clean test data with no attack, PointNet outperforms all the robust classifiers by small margins. (2) Using both attackers, our LPC variants work consistently and significantly better than the other defender-based robust classifiers as well as vanilla PointNet by large margins. For instance, compared with PointNet with IF-Defense under the JGBA attacks, the performance gaps are 84.14\% and 69.71\% on ModelNet40 and ScanNet, respectively. (3) For the backbone networks in LPC, it seems that the difference in performance is small among different CNNs. Though more evaluations are needed to confirm this, it also demonstrates the robustness of our approach.

\begin{figure}
    \center
    \includegraphics[width=.9\columnwidth]{figures/distribution.pdf}
    \vspace{-3mm}
	\caption{Distribution comparison of successful perturbation attacks on ModelNet40. To avoid the sparsity, LPC statistics are collected based on the cases from all the three models.}
	\label{fig:iter_num}
	\vspace{-4mm}
\end{figure}

\subsubsection{Attack Success Rate}

\bfsection{Performance summary}
We list our comparison in Table \ref{table:attack_main} and Table \ref{table:lggan_attack}. We can see that: (1) Our LPC variants achieve perfect results under both FGSM and JGBA attacks. Notice that compared with the other attackers, these two attackers aim to find adversarial examples fully based on gradients with no sampling. Their failure again strongly demonstrates the power of implicit gradients in defending gradient based adversarial attacks. (2) The SOR defense mechanism seems to work better for the perturbation and add attackers, but worse for the cluster and object attackers, compared with our LPC. However, overall LPC still achieves the best performance.
(3) Our LPC also outperforms other defenses under GAN based attacks. Interestingly RPL \cite{gould2021deep} outperforms SOR defenses under LG-GAN attack, while under gradient based attacks the SOR methods are better. It implies LG-GAN has better transferability. The two SOR based defenses are gray-box attacks (partial access to the model). Gradient based adversarial samples suffer significant success rate drop as shown in Table \ref{table:attack_main}. But LG-GAN transfers well to SOR based defenses, maintaining over $10\%$ attack success rate.

Using the TSI/CTRI attacker \cite{zhao2020isometry}, our LPC with EfficientNet-B5 achieves the same success rate for both TSI and CTRI attackers on ModelNet40. Without random rotation, the result is 99.54\%, but with random rotation, the performance decreases to 67.33\% which is significantly better than PointNet (99.50\% and 99.55\% for TSI and CTRI, respectively). Such results also demonstrate that random rotation to point clouds as a means of data augmentation improves not only accuracy but also model robustness.

\begin{figure}
    \center
    \includegraphics[width=\columnwidth]{figures/pert_lr.pdf}
    \vspace{-8mm}
	\caption{Successful adversarial perturbation examples on ModelNet40 for LPC with EfficientNet-B5.}
	\label{fig:succ_sample}
	\vspace{-4mm}
\end{figure}

\bfsection{Importance of gradients in finding successful adversarial examples for LPC}
To attack each point cloud, the four targeted attackers in \cite{xiang2019generating} conduct 10 random searches where 500 iterations are done to find the optimal adversarial samples. We notice that for PointNet, the best attacks could occur at any time within these 500 iterations, but for our LPC most optimal attacks happen at the first few iterations, as shown in Fig.~\ref{fig:iter_num} with different learning rates for the perturbation attacker. This behavior indicates that, in order to attack LPC, random search (a sampling based method) has contributed more to most of the successful attacks, rather than gradient-based iterations. With the increase of the learning rate, the gradients start to find more optimal adversarial samples. However, as we illustrate in Fig. \ref{fig:succ_sample}, with larger learning rates, the adversarial samples will not look similar to the original point clouds. For instance, with learning rate of 1, the point cloud of airplane has been totally changed to a mixture of smaller airplane point clouds, which is not an adversarial attack anymore. To sum up, such analysis again demonstrates the great potential of implicit gradients in defending adversarial attacks.

\section{Conclusion}
In this paper, we aim to address the problem of robust 3D point cloud classification by proposing a family of novel robust structured declarative classifiers, where a declarative node is defined by a constrained optimization problem such as the reconstruction of point clouds. The key insight in our approach is that the implicit gradients through the declarative node can help defend the adversarial attacks by leading them to wrong updating directions for inputs. We formulate the learning of our classifiers based on bilevel optimization, and further propose an effective and efficient instantiation, namely, Lattice Point Classifier (LPC). The declarative node in LPC is defined as structured sparse coding in the permutohedral lattice, whose outputs, \emph{i.e., } barycentric weights, are further transformed into images for classification using 2D CNNs. LPC is end-to-end trainable, and achieves state-of-the-art performance on robust classification on ModelNet40 and ScanNet using seven different adversarial attackers.

\bfsection{Limitations}
Currently the projection in the permutohedral lattice transformation in LPC is not learned but simply fixed as initialization. Also more evaluations for demonstrating the robustness of our approach across different backbone networks and datasets are desirable. Therefore, in our future work we will investigate more on how to properly learn the projection with its physical conditions and conduct more experiments to further demonstrate our robustness.

\section*{Acknowledgement}
K. Li and C. Zhong were supported in part by USDA NIFA under the award no. 2019-67021-28996. Z. Zhang was supported in part by NSF grant CCF-2006738. G. Wang was partly supported by NSERC grant RGPIN-2021-04244.

\balance
{\small
\bibliographystyle{ieee_fullname}

redpajama_set_name: RedPajamaArXiv